0

I want to update nested _ids over an entire collection IF they are of a type string.

If I have object that look like this...

user : {
    _id: ObjectId('234wer234wer234wer'),
    occupation: 'Reader',
    books_read: [
        {
           title: "Best book ever",
            _id: "123qwe234wer345ert456rty"
        },
        {
           title: "Worst book ever",
            _id: "223qwe234wer345ert456rty"
        },
        {
           title: "A Tail of Two Cities",
            _id: ObjectId("323qwe234wer345ert456rty")
        }
    ]
}

and I want to change the type of the _Ids from string to ObjectId

how would I do that.??

I have done "this" in the past...But this is working on NON-nested item - I need to change a nested value

 db.getCollection('users')
.find({
  $or: [
    {occupation:{$exists:false}},
    {occupation:{$eq:null}}
  ]
})
.forEach(function (record) {
  record.occupation = 'Reader';
  db.users.save(record);
});

Any help - I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'

klhr
  • 3,300
  • 1
  • 11
  • 25
j-p
  • 3,698
  • 9
  • 50
  • 93

1 Answers1

0

There isn't a way of doing (non $rename) updates operations on a document while referencing existing fields -- MongoDB: Updating documents using data from the same document

So, you'll need to write a script (similar to the one you posted with find & each) to recreate those documents with the correct _id type. To find the subdocuments to update you can use the $type operator. A query like db.coll.find({nestedField._id: {$type: 'string' }}) should find all the full documents that have bad subdocuments, or you could do an aggregation query with $match & $unwind to only get the subdocuments

db.coll.aggregate([
  { $match: {'nestedField._id': {$type: 'string' }}}, // limiting to documents that have any bad subdocuments
  { $unwind: '$nestedField'}, // creating a separate document in the pipeline for each entry in the array
  { $match: {'nestedField._id': {$type: 'string' }}}, // limiting to only the subdocuments that have bad fields
  { $project: { nestedId: 'nestedField._id' }} // output will be: {_id: documentedId, nestedId }
])

I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'

You can run js code directly on the mongo to avoid making api calls, but I don't think there's any way to avoid looping over the documents.

klhr
  • 3,300
  • 1
  • 11
  • 25