2

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:

  1. What is query to update text="Completed Successfully" and test="Done" where _id" : ObjectId("571dea148234534308a290e").test_id=1.

  2. 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

vogash
  • 930
  • 1
  • 10
  • 15

2 Answers2

2

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

pupizoid
  • 301
  • 1
  • 12
0

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}
);
White Bullet
  • 205
  • 2
  • 11