Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB, change array of objects to an array of strings containing their ObjectId

I have an database full of objects that contain information, as well as other arrays of objects. I would like to change the inner arrays to only be arrays with each index as an ObjectId type with their respective ObjectId

I am using the mongoose populate function to retrieve this information later in the program. So only the ObjectId is needed for the reference.

job { 
    _id: 1,
    name: "name",
    parts: [ 
        { _id: ObjectId("5c790ce7d3dc8d00ccc2688c"), name: "name"},
        { _id: ObjectId("5c790ce7d3dc8d00ccc2688b"), name: "name"},
        { _id: ObjectId("5c790ce7d3dc8d00ccc2688a"), name: "name"},
    ]
}

Desired Result

job {
    _id: 1,
    name: "name",
    parts: [
        ObjectId("5c790ce7d3dc8d00ccc2688c"),
        ObjectId("5c790ce7d3dc8d00ccc2688b"),
        ObjectId("5c790ce7d3dc8d00ccc2688a")
    ]
}

I tried a few mongoDB queries from the command line but none of them are quite giving the result I need. This one has no errors, but it doesn't seem to change anything.

db.jobs.update(
    {},
    {
        $set: {"parts.$[element]": "element._id"}
    },
    {
        multi: true,
        arrayFilters: [{ "element": {} }]
    }
)

I'm not sure if this is possible or not using only the mongo shell.

like image 328
nmfb Avatar asked Sep 02 '25 07:09

nmfb


1 Answers

Mongo v4.2 introduced pipelined updates this allows the use of aggregation operators within the update and more importantly updating a document using it's own values. which is what you want to achieve.

db.jobs.updateMany(
    {},
    [
        {
            '$set': {
                'parts': {
                    '$map': {
                        'input': '$parts',
                        'as': 'part',
                        'in': '$$part._id'
                    }
                }
            }
        }
    ]);

Unfortunately this is not possible for earlier Mongo versions. Specifically $arrayFilters allows you to filter an array but again prior to the new update syntax accessing own values within the update is not possible.

You'll have to iterate over all documents and do the update one by one in code.

like image 192
Tom Slabbaert Avatar answered Sep 05 '25 00:09

Tom Slabbaert