3

This code uses a loop to $unset the "checked" property of all embedded documents in the "value" array, then $set the one when a condition evaluates to true.
But when the condition is true, the update block failed to update the embedded document by setting a checked: "checked", I know that because meteor:PRIMARY> db.radioOptions.find({}).pretty(); gives the same results before and after.

What am I doing wrong? and how to fix it? Thanks

meteor:PRIMARY> db.radioOptions.find({}).pretty();
{
 "_id" : "jXQcsXtedQYotKQXG",
 "name" : "optionType",
 "value" : [
  {
   "name" : "1stOption",
   "caption" : "1st Option"
  },
  {
   "name" : "2ndOption",
   "caption" : "2nd Option"
  }
 ]
}


      var doc = RadioOptions.findOne({name: obj.name});
      if (typeof doc != 'undefined') {
        doc.value.forEach(function (embdoc) {
          console.log(embdoc);
          RadioOptions.update(
            {name: obj.name, 'value.name': obj.value},
            {$unset: {'value.$.checked': ""}}
          );
          if (embdoc.name == obj.value) {
              console.log(obj.name + " " + obj.value); //obj.value = 1stOption for example
              RadioOptions.update(
              {name: obj.name, 'value.name': obj.value}, //obj.name = "optionType"
              {$set: {'value.$.checked': "checked"}}
            );

          }
        })
      }
Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
Fred J.
  • 5,759
  • 10
  • 57
  • 106

1 Answers1

0

Let's say that is was your objective to set the array element with the name "2ndOption" to "checked" and $unset all other array elements. You would then instead do:

  var doc = RadioOptions.findOne({name: obj.name});
  if (typeof doc != 'undefined') {
    // You have to update every element
    doc.value.forEach(function (embdoc) {
       RadioOptions.update(
           { "_id": doc._id, "value.name": embdoc.name },
           { "$unset": { "value.$.checked": "" } }
       ) 
    });
    // Then just set the one you want
    RadioOptions.update(
       { "_id": doc._id, "value.name": "2ndOption" }, // <-- actually using a variable of course
       { "$set": { "value.$.checked": "checked" } }
    ) 
  }

Now if you had actually read all the responses on the duplicate question you were given for your original question:

How to Update Multiple Array Elements in mongodb

Then you would have seen the response there that mentioned the best way to handle all these mutliple updates was using the "Bulk" API methods in the underlying driver. And also has some useful tips on the general process of updating multiple elements.

On the "server" (not in minimongo) is the best place to to this, and all meteor collections have a .rawCollection() method which returns the collection object from the underlying node native driver.

So the general logic is:

  • Loop all array elements and update to "turn off"
  • Match the element you want to "turn on"

And best done in Bulk rather than responding back and forth for each update.

Community
  • 1
  • 1
Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • 1
    If you already have the document in memory (you've done a findOne), why not just modify the `value` field as needed and then `$set` the entire thing rather than doing dozens of updates? This isn't a criticism, I'm just wondering if that was a parameter of the question that I missed. – David Weldon Mar 11 '16 at 15:13