MongoDB: How to update an entire document in a collection - mongodb

In my application I need to edit a document... and while editing the document the current [unchanged] version should be still available to other users. For instance, when I start editing a document, I create a new copy of it in a separate collection, and when done I replace the current version with the new version of the temporary collection.
Let's assume the original document stored in collection users looks like this:
{
"_id" : ObjectId("53b986e2fe000000019a5a13"),
"name" : "Joe",
"birthDate" : "2080-12-11",
"publications" : [
{ "title" : "title 1", "description" : "description 1" },
{ "title" : "title 2", "description" : "description 2" }
]
}
Then, let's assume the document above is copied to another collection (e.g. users.wip) and modified like this:
{
"_id" : ObjectId("53b986e2fe000000019a5a13"),
"name" : "Joe",
"birthDate" : "1980-12-11",
"publications" : [
{ "title" : "bye bye", "description" : "Blah blah" },
{ "title" : "title 2", "description" : "description 2" },
{ "title" : "title 3", "description" : "description 3" }
]
}
How do I replace the whoe document? The problem is that when I try to update the original document with
{ "$set" : {
"name" : "Joe",
"birthDate" : "1980-12-11",
"publications" : [
{ "title" : "bye bye", "description" : "Blah blah" },
{ "title" : "title 2", "description" : "description 2" },
{ "title" : "title 3", "description" : "description 3" }
]
}}
I always get the following error message:
10150 Field name duplication not allowed with modifiers
That said, what's the correct way to update an entire document?

To replace the whole document, you don't use $set, but just provide the new doc to the update call:
db.test.update({"_id": ObjectId("53b986e2fe000000019a5a13")}, {
"_id" : ObjectId("53b986e2fe000000019a5a13"),
"name" : "Joe",
"birthDate" : "1980-12-11",
"publications" : [
{ "title" : "bye bye", "description" : "Blah blah" },
{ "title" : "title 2", "description" : "description 2" },
{ "title" : "title 3", "description" : "description 3" }
]
})
However, with the current 3.0 driver, it would be best to use replaceOne instead:
db.test.replaceOne({"_id": ObjectId("53b986e2fe000000019a5a13")}, {
"name" : "Joe",
"birthDate" : "1980-12-11",
"publications" : [
{ "title" : "bye bye", "description" : "Blah blah" },
{ "title" : "title 2", "description" : "description 2" },
{ "title" : "title 3", "description" : "description 3" }
]
})

Related

I would like to add couple of fields from a collection(Release) into another collection(Story)based on matching conditions(ID) in Mongo DB

Collection: Story ( This is the main collection where 2 fields from the release collection needs to be appended.)
{
"_id" : ObjectId("5d131d93e2838c3b753e6631"),
"expand" : "schema,names",
"total" : 2,
"issues" : [
{
"expand" : "operations,versionedRepresentations,editmeta,changelog,renderedFields",
"id" : "131",
"fields" : {
"updateddate" : "2019-06-12T10:58:12.345+0530",
"fixVersions" : [
{
"id" : "10008",
"description" : "New Release 2",
"name" : "New Release 2"
},
{
"id" : "10009",
"description" : "New Release 3",
"name" : "New Release 3"
}
],
"aggregatetimespent" : null
}
},
{
"expand" : "operations,versionedRepresentations,editmeta,changelog,renderedFields",
"id" : "10032",
"fields" : {
"updateddate" : "2019-06-22T10:58:12.345+0530",
"fixVersions" : [
{
"id" : "10008",
"description" : "New Release 2",
"name" : "New Release 2"
}
],
"aggregatetimespent" : null
}
}
]
}
Collection: Release( This is another collection with few fields from which fields)
{
"_id" : ObjectId("5d131a35e2838c3b753e6626"),
"id" : "10008",
"startDate" : "2019-06-28",
"releaseDate" : "2019-07-05"
}
{
"_id" : ObjectId("5d131a35e2838c3b753e6626"),
"id" : "10009",
"startDate" : "2019-08-28",
"releaseDate" : "2019-09-05"
}
Start date and Release Date need to be appended to the array fields based on the condition.
Expected output:
Collection: Story
{
"_id" : ObjectId("5d131d93e2838c3b753e6631"),
"expand" : "schema,names",
"total" : 2,
"issues" : [
{
"expand" : "operations,versionedRepresentations,editmeta,changelog,renderedFields",
"id" : "131",
"fields" : {
"updateddate" : "2019-06-12T10:58:12.345+0530",
"fixVersions" : [
{
"id" : "10008",
"description" : "New Release 2",
"name" : "New Release 2",
"startDate" : "2019-06-28",
"releaseDate" : "2019-07-05"
},
{
"id" : "10009",
"description" : "New Release 3",
"name" : "New Release 3",
"startDate" : "2019-08-28",
"releaseDate" : "2019-09-05"
}
],
"aggregatetimespent" : null
}
},
{
"expand" : "operations,versionedRepresentations,editmeta,changelog,renderedFields",
"id" : "10032",
"fields" : {
"updateddate" : "2019-06-22T10:58:12.345+0530",
"fixVersions" : [
{
"id" : "10008",
"description" : "New Release 2",
"name" : "New Release 2",
"startDate" : "2019-06-28",
"releaseDate" : "2019-07-05"
}
],
"aggregatetimespent" : null
}
}
]
}

MongoDB self join(aggregation) of collection with parent references

Hello I have this collection, with parent references, I need to do self join on this collection, so that output will contain the children to maximum depth in one document and also get the output based on "Type" field.
{
"DescId" : "1",
"Desc" : "Testing",
"ParentId" : "null",
"Order" : 1.0,
"Type" : "A",
"Parent" : null
}
{
"DescId" : "1.1",
"Desc" : "Testing Child 1",
"ParentId" : "1",
"Order" : 1.0,
"Type" : "B",
"Parent" : "Testing"
}
{
"DescId" : "1.2",
"Desc" : "Testing Child 2",
"ParentId" : "1",
"Order" : 2.0,
"Type" : "B",
"Parent" : "Testing"
}
{
"DescId" : "1.1.1",
"Desc" : "Testing grand child 1",
"ParentId" : "1.1",
"Order" : 1.0,
"Type" : "C",
"Parent" : "Testing Child 1"
}
At present I have this output based on answer given to my previous question:
{
"ADescId" : "1",
"ADesc" : "Testing"
}
{
"BDescId" : "1.1",
"BDesc" : "Testing child 1"
}
{
"BDescId" : "1.2",
"BDesc" : "Testing Child 2"
}
{
"CDescId" : "1.1.1",
"CDesc" : "Testing grandchild 1"
}
I have tried doing $graphlookup aggregation on this collection, somehow data seems to get messed up. Please let me know if there is a way to achieve this. Thanks.
Desired output:
{
"ADescId" : "1",
"ADesc" : "Testing",
"BDescId" : "1.1",
"BDesc" : "Testing child 1",
"CDescId" : "1.1.1",
"CDesc" : "Testing grandchild 1"
}
{
"ADescId" : "1",
"ADesc" : "Testing",
"BDescId" : "1.2",
"BDesc" : "Testing Child 2"
}

Segregate results from mongodb based on a particular field

My schema for list collection is-
list:
{
username : "some username",
listitem : "some item",
category : "some category",
status : "some status"
}
db.list.find() gets all the results, but I want to retrieve data based on category where the results with same category value appear together.Here is sample output of
db.list.find()
{
"_id" : ObjectId("585669eb4aa058f4e7972db3"),
"username" : "user1",
"listitem" : "item 1",
"status" : "P",
"category" : "A",
}
{
"_id" : ObjectId("5856a7c64aa058f4e7972db4"),
"username" : "user2",
"listitem" : "item 2",
"status" : "p",
"category" : "B",
}
{
"_id" : ObjectId("5858faedde3ffb11a083e770"),
"username" : "user1"
"listitem" : "item 3",
"status" : "p",
"category" : "A",
}
But I want all my 'A' category results together and 'B' category results together.
that is,output should be like this-
{
"_id" : ObjectId("5856a7c64aa058f4e7972db4"),
"username" : "user2",
"listitem" : "item 2",
"status" : "p",
"category" : "B",
}
{
"_id" : ObjectId("585669eb4aa058f4e7972db3"),
"username" : "user1",
"listitem" : "item 1",
"status" : "P",
"category" : "A",
}
{
"_id" : ObjectId("5858faedde3ffb11a083e770"),
"username" : "user1"
"listitem" : "item 3",
"status" : "p",
"category" : "A",
}
Please someone tell me how to do this.Whether this directly possible through mongodb query or I have to perform operations to format output in this form, when I get result in node js server?
It is a simple use case of sort
db.list.find().sort( { category: 1 } )
All the docs will be sorted by the corresponding category values and hence, all docs with the same category value will be listed together.

Spring rest docs nested object

We need to deliver a response for a call in the following form:
{
"3" : {
"id" : "3",
"parent" : "1",
"title" : "Folder 2",
"folder" : true
},
"4" : {
"id" : "4",
"parent" : "2",
"title" : "Folder 1.1",
"folder" : true
},
"doc:3" : {
"parent" : "3",
"title" : "Document 3",
"folder" : false
},
"doc:2" : {
"parent" : "2",
"title" : "Document 2",
"folder" : false
},
"doc:1" : {
"parent" : "3",
"title" : "Document 1",
"folder" : false
}
}
How should i document it? The Problem is that the object is a structure with EntryId as key and contains no id when its a document. Is there a option where I can use variables to define keys? Or whats recomended to use in responseFields ?
I had the same problem that Andy Wilkinson is pointing in the comments and instead of hardcode it in the ascii.doc, I did it like so:
,relaxedResponseFields(
fieldWithPath("key").description(getMessage(MessageProperties.TRANSLATION_RESOURCE_MAP_KEY)).type(MessageProperties.TYPE_STRING).optional(),
fieldWithPath("value").description(getMessage(MessageProperties.TRANSLATION_RESOURCE_MAP_KEY_VALUE)).type(MessageProperties.TYPE_MAP).optional(),
fieldWithPath("value[].key").description(getMessage(MessageProperties.TRANSLATION_RESOURCE_MAP_KEY_VALUE_KEY)).type(MessageProperties.TYPE_LONG).optional(),
fieldWithPath("value[].value").description(getMessage(MessageProperties.TRANSLATION_RESOURCE_MAP_KEY_VALUE_KEY_VALUE)).type(MessageProperties.TYPE_STRING).optional()
)
check How to document response fields for an object as Map(HashMap) for more info of the problem and if it really like yours.

MongoDB update complex document

I search for some similar example, but didn't find something good.
{
"_id" : ObjectId("571dea148234534308a290e"),
"user" : "myusername",
"duration" : "",
"test_details" : [
{
"test" : "New",
"test_id" : "0",
"comments" : "will be some text",
"text" : ""
},
{
"test" : "**to change value here**",
"test_id" : "1",
"comments" : "will be some text",
"text" : "**to change value here**"
},
{
"test" : "New",
"test_id" : "2",
"comments" : "will be some text",
"text" : ""
},
{
"test" : "New",
"test_id" : "3",
"comments" : "will be some text",
"text" : ""
"sub_test_details" : [
{
"56eed334534566ac5668ca18" : [
{
"sub_test" : "New",
"sub_test_id" : "0",
"sub_comments" : "will be some text",
"sub_text" : ""
},
{
"sub_test" : "New",
"sub_test_id" : "1",
"sub_comments" : "will be some text",
"sub_text" : ""
},
{
"sub_test" : "New",
"sub_test_id" : "2",
"sub_comments" : "will be some text",
"sub_text" : ""
}
]
},
{
"56eed3b1f37d66ac5668ca19" : [
{
"sub_test" : "New",
"sub_test_id" : "0",
"sub_comments" : "will be some text",
"sub_text" : ""
},
{
"sub_test" : "New",
"sub_test_id" : "1",
"sub_comments" : "will be some text",
"sub_text" : ""
},
{
"sub_test" : "**to change value here**",
"sub_test_id" : "2",
"sub_comments" : "will be some text",
"sub_text" : "**to change value here**"
}
]
}
]
},
{
"test" : "New",
"test_id" : "4",
"comments" : "will be some text",
"text" : ""
}
],
}
And the questions are:
What is query to update text="Completed Successfully" and test="Done" where _id" : ObjectId("571dea148234534308a290e").test_id=1.
What is query to update sub_text="Sub Completed Successfully" and sub_test="Sub Done" where _id" : ObjectId("571dea148234534308a290e").test_details.test_id=3.sub_test_details.56eed3b1f37d66ac5668ca19.sub_step_id=2
In my case i will get id, test_id, exam_num(56eed3b1f37d66ac5668ca19), sub_test_id will be parameters to find relevant place for updating.
An array elements size not always constant. Therefore I use id to specify exactly which element I am looking for.
Thanks
MongoDB allows using indexes while updating nested documents, so the query for your first question should be most likely this:
db.test.update({"_id": ObjectId("571dea148234534308a290e"), "test_details.test_id": "1"}, {"$set": {"test_details.$.test": "Done", "test_details.$.text": "Completed Succesfully"}})
Unfortunately this works only on first level of embedding, so you can't use more than one positional operator $. There are two ways to change embedded data in this case: first, you should know index of the document you want to update, and the second requires some data structure changes. Instead of using lists to hold nested documents in your test_details you should use dictionary, in this way:
{
"test" : "New",
"test_id" : "3",
"text" : ""
"sub_test_details" : {
"56eed334534566ac5668ca18" : {
"0": {
"sub_test" : "New",
"sub_text" : ""
},
"1": {
"sub_test" : "New",
"sub_text" : ""
},
"2": {
"sub_test" : "New",
"sub_text" : ""
}
},
"56eed3b1f37d66ac5668ca19" : {
"0": {
"sub_test" : "New",
"sub_text" : ""
},
"1": {
"sub_test" : "New",
"sub_text" : ""
},
"2": {
"sub_test" : "**to change value here**",
"sub_text" : "**to change value here**"
}
}
}
}
and the query will be like this:
db.test.update({"_id": ObjectId("571e32c0907445669f11037e"), "test_details.test_id": "3"}, {"$set": {"test_details.$.sub_test_details.56eed334534566ac5668ca18.0.sub_test": "Done", "test_details.$.sub_test_details.56eed334534566ac5668ca18.0.sub_text": "Completed Succesfully"}})
Also see this question where similar problems are discussed
The update method should do that for you, you should use $addToSet, to ensure no duplicates go into an array given the id, and upsert:true to update existing docs with the same id. The below should work
db.tests.update(
{_id" : ObjectId("571dea148234534308a290e"},
{$addToSet:
{ test_details:
{test_id: "0",
test: "Done",
text: "Completed Successfully"
}}},
{upsert: true}
);