0

I would like to preface this with saying that english is not my mother tongue, if any of my explanations are vague or don't make sense, please let me know and I will attempt to make them clearer.

I have a document containing some nested data. Currently product and customer are arrays, I would prefer to have them as straight up ObjectIDs.

    {
            "_id" : ObjectId("5bab713622c97440f287f2bf"),
            "created_at" : ISODate("2018-09-26T13:44:54.431Z"),
            "prod_line" : ObjectId("5b878e4c22c9745f1090de66"),
            "entries" : [
                    {
                            "order_number" : "123",
                            "product" : [
                                    ObjectId("5ba8a0e822c974290b2ea18d")
                            ],
                            "customer" : [
                                    ObjectId("5b86a20922c9745f1a6408d4")
                            ],
                            "quantity" : "14"
                    },
                    {
                            "order_number" : "456",
                            "product" : [
                                    ObjectId("5b878ed322c9745f1090de6c")
                            ],
                            "customer" : [
                                    ObjectId("5b86a20922c9745f1a6408d5")
                            ],
                            "quantity" : "12"
                    }
            ]
    }

I tried using the following query to update it, however that proved unsuccessful as Mongo didn't behave quite as I had expected.

    db.Document.find().forEach(function(doc){
            doc.entries.forEach(function(entry){
                    var entry_id = entry.product[0]
                    db.Document.update({_id: doc._id}, {$set:{'product': entry_id}});
                    print(entry_id)
                    })
    })

With this query it sets product in the root of the object, not quite what I had hoped for. What I was hoping to do was to iterate through entries and change each individual product and customer to be only their ObjectId and not an array. Is it possible to do this via the mongo shell or do I have to look for another way to accomplish this? Thanks!

3 Answers 3

2

In order to accomplish your specified behavior, you just need to modify your query structure a bit. Take a look here for the specific MongoDB documentation on how to accomplish this. I will also propose an update to your code below:

db.Document.find().forEach(function(doc) {
    doc.entries.forEach(function(entry, index) {
        var productElementKey = 'entries.' + index + '.product';
        var productSetObject = {};
        productSetObject[productElementKey] = entry.product[0];
        db.Document.update({_id: doc._id}, {$set: productSetObject});
        print(entry_id)
    })
})

The problem that you were having is that you were not updating the specific element within the entries array, but rather adding a new key to the top-level of the document named product. Generally, in order to set the value of an inner document within an array, you need to specify the array key first (entries in this case) and the inner document key second (product in this case). Since you are trying to set specific elements within the entries array, you need to also specify the index in your query object, I have specified above.

In order to update the customer key in the inner documents, simply switch out the product for customer in my above code.

Sign up to request clarification or add additional context in comments.

Comments

0

You're trying to add a property 'product' directly into your document with this line

db.Document.update({_id: doc._id}, {$set:{'product': entry_id}});

Try to modify all your entries first, then update your document with this new array of entries.

db.Document.find().forEach(function(doc){
        let updatedEntries = [];
        doc.entries.forEach(function(entry){
            let newEntry = {};

            newEntry["order_number"] = entry.order_number;
            newEntry["product"] = entry.product[0];
            newEntry["customer"] = entry.customer[0];
            newEntry["quantity"] = entry.quantity;

            updatedEntries.push(newEntry);
       })
       db.Document.update({_id: doc._id}, {$set:{'entries': updatedEntries}});
})

Comments

0

You'll need to enumerate all the documents and then update the documents one and a time with the value store in the first item of the array for product and customer from each entry:

db.documents.find().snapshot().forEach(function (elem) {
    elem.entries.forEach(function(entry){

        db.documents.update({
                _id: elem._id,
                "entries.order_number": entry.order_number
            }, {
                $set: {
                    "entries.$.product" : entry.product[0],
                    "entries.$.customer" : entry.customer[0]
                }
            }
        );
    });
});

Instead of doing 2 updates each time you could possibly use the filtered positional operator to do all updates to all arrays items within one update query.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.