0

In my Mlab mongo 3.2 database I have a collection that looks like this:

{
"_id": {
    "$oid": "5752d....87985"
},
"name": "...etation",
"description": null,
"user_id": ".....",
"questions": [
    {
        "prompt": "The conclusions drawn seemed clear to most researchers, however, others were unconvinced, arguing that everything is open to ____________.",
        "answer": "interpretation",
        "created_at": "2014-11-09T14:59:38.154",
        "updated_at": "2014-11-09T14:59:38.154",
        "filled_answer": null
    },
    {
        "id": 922,
        "prompt": "His existential quest for Truth is in fact the key to his understanding and ____________ of the Bhagavad-Gītā.",
        "answer": "interpretation",
        "created_at": "2014-10-03T08:07:40.295",
        "updated_at": "2014-10-03T08:07:40.295",
        "filled_answer": null
    },
}

There are two problems with the questions subdocument that I am struggling with:

  1. Sometimes but not always there is a legacy "id" field that I want to $unset but my query is not working.

  2. I want to add an _id ObjectID field where they do not already exist. Currently some have them and some don't.

I have tried a number of queries but none seem to work. For example:

db.droplets.updateMany({"questions.$._id": { $exists: false }},{ $set: {"questions.$._id": new ObjectId()}},{"multi": true, "upsert": true})

Mongo tells me "The positional operator did not find the match needed from the query"

Update

I have successfully found a way to delete all the questions using the following script:

db.droplets4.find().forEach(function (doc) { 
  doc.questions.forEach(function (question) { 
    if (question.id) {
      delete question.id
    }
  });
  db.droplets.save(doc);
});

But the same strategy is not working for adding Object IDs. This code does not work:

db.droplets4.find().forEach(function (doc) { 
  doc.questions.forEach(function (question) { 
    if (!question._id) { question._id = new ObjectId() }
  });
  db.droplets.save(doc);
});
Community
  • 1
  • 1
Finnjon
  • 651
  • 4
  • 19
  • Because you mean `.updateMany({ "questions._id": { "$exists": false } }, { ...`. The positional operator is for use in the "update" document, and not the "query" itself. – Neil Lunn Jul 21 '17 at 08:41
  • You also should note that the [positional `$` operator](https://docs.mongodb.com/manual/reference/operator/update/positional/) also only ever matches the "first" matched index position in an array. In order to update "all array elements" that are missing the information, you actually need a form of "looping" to update. This is described in the better answers of ["How to Update Multiple Array Elements in mongodb"](https://stackoverflow.com/q/4669178/2313887). Note that "most votes" does not mean "better" in this case in particular. – Neil Lunn Jul 21 '17 at 08:45
  • Thanks for the answer. This is now working for removing the field using: db.droplets4.updateMany({"questions.id": { $exists: true }},{ $unset: {"questions.$.id": ""}}) but I am still getting the error when I try to add an ID. And yes, you are right it only updates the first one each time. I will take a look at your link. – Finnjon Jul 21 '17 at 08:52

1 Answers1

0

This should work fine for you

db.droplets4.updateMany( { 
        "questions._id" : null
    },{ $set: {"questions.$._id": new ObjectId()}},{"multi": true, "upsert": true})
Swadesh
  • 651
  • 2
  • 8
  • 22