简体   繁体   中英

With MongoDB, how do I update an object within in array with an object from a variable?

I have an object assigned to a variable, such as:

var child = {
    { 
        _id: 'ObjectID("16e7f7baa05c3a9d751363")',
        title: 'Testing',
        sort: 3,
        active: true 
    }

The following does not work, and honestly I am unsure of what I'm missing:

db.category.update(
    { _id: "thisistheparentdocumentsid", "children._id": child._id },
    {
        $set: {
            "children.$.title": child.title,
            "children.$.active": child.active,
            "children.$.sort": child.sort
        }
    }
);

What I really want to do, as I want to reuse this method and not repeat myself later is:

db.category.update(
    { _id: "thisistheparentdocumentsid", "children._id": child._id },
    {
        $set: {
            "children" : child
        }
    }
);

That doesn't work either. I referenced this post: Update array element by id with mongo query

As well as: http://docs.mongodb.org/manual/reference/operator/update/positional/

But my query is not working. Am I missing something elementary here?

--- Edit ---

Here is the result when I query based on the parent document

db.category.findOne({ "_id" : "9dYgKdfFczgiRcNouij"});
{
        "title" : "ParentTest",
        "active" : true,
        "children" : [
                {
                        "_id" : ObjectId("680d55c6995ef6f0748278c2"),
                        "title" : "ChildTest",
                        "active" : true
                                            },
                {
                        "_id" : ObjectId("2b4469c1a4c8e086942a1233"),
                        "title" : "ChildTest2"
                        "active" : true
                }
        ],
        "_id" : "9dYgKdfFczgiRcNouij"
}

I'm passing data to the server, such as... Method.call("UpdateCommand", id, child);

The variable id is the parent id of the document, and the child is the object I mentioned.

I use child._id.toString() to generate the matching ObjectId("...");

So more specifically:

db.category.update(
        { _id: id, "children._id": child._id.toString() },
        {
            $set: {
                "children.$.title": child.title,
                "children.$.active": child.active,
                "children.$.sort": child.sort,
                "children.$.uppercase": child.title.toUpperCase()
            }
        }
    );

Yet this doesn't work. I'm thinking something is off with my selector, but I can use findOne() with the same method and it does return the proper document, and using $elemMatch returns the specified child item in the array.

Anything I might be missing? I've ran all the values through console.log to make sure I'm getting them, and I am.

So what you are saying is that you have a document like this:

{
    "_id": ObjectId("5430b55d214047b8ee55d40b"),
    "children": [
        { 
            "_id": ObjectID("16e7f7baa05c3a9d751363"),
            "title": "Testing",
            "sort": 2,
            "active": false 
        }
    }
}

Or something similar, but at least with an array of children like that. As long as you are happy to update "all" if the elements in the "child" entry with the values in your variable object then there is nothing wrong with this:

db.category.update(
    { "_id": ObjectId("5430b55d214047b8ee55d40b"), "children._id": child._id },
    { "$set": { "children.$": child }
)

And that will replace the entire element in position.

If you are worried about replacing the entire content where you might have something like this:

{
    "_id": ObjectId("5430b55d214047b8ee55d40b"),
    "children": [
        { 
            "_id": ObjectID("16e7f7baa05c3a9d751363"),
            "title": "Testing",
            "sort": 2,
            "active": false,
            "created": ISODate("2014-10-03T03:09:20.609Z")
        }
    }
}

Then you can process the keys of the object to construct your $set statement:

var update = { "$set": {} };

for ( var k in child ) {
    if ( k != "_id" )
        update["$set"]["children.$."+k] = child[k];
}

db.category.update(
    { "_id": ObjectId("5430b55d214047b8ee55d40b"), "children._id": child._id },
    update
);

Which will process the update in place but does not overwrite the "created" field that was not supplied.

Also note your quotes '' around the ObjectId value there, but I'm hoping that is just a typo, otherwise you need to eval() the string to get a valid object.

The single array elements here are just and example. It is the positional $ operator syntax with the matching element in the query that matters here. There is no difference for a single array element or hundreds. Just as long as you are only updating one element of the array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM