Foo.$[].bar is not allowed by the Schema

I have a Documents in a Collection that have a field that is an Array (foo). This is an Array of other subdocuments. I want to set the same field (bar) for each subdocument in each document to the same value. This value comes from a checkbox.

So…my client-side code is something like

'click #checkAll'(e, template) {
    const target = e.target;
    const checked = $(target).prop('checked');

    //Call Server Method to update list of Docs
    const docIds = getIds();
    Meteor.call('updateAllSubDocs', docIds, checked);
 }

I tried using https://docs.mongodb.com/manual/reference/operator/update/positional-all/#positional-update-all

And came up with the following for my Server helper method.

'updateAllSubDocs'(ids, checked) {
     Items.update({ _id: { $in: ids } }, { $set: { "foo.$[].bar": bar } },
      { multi: true }, function (err, result) {
        if (err) {
          throw new Meteor.Error('error updating');
        }
      });
 }

But that throws an error ‘foo.$.bar is not allowed by the Schema’. Any ideas?
I’m using SimpleSchema for both the parent and subdocument

Thanks!

ok, my understanding: you collection named Documents. Within the Documents you have objects that look like this:

{
   _id: 'xxxxxx',
   foo: [
      {
        bar: '......'
      },
      {
         bar: '.....'
      }   
   ]
}

Your object inside the array is foo.$ not foo.$[]

You are correct. So I have a list of Documents that I want to update and I update using $in: ids.

I would like to set each bar in the example above to the same value. I updated my syntax to what you have and am receiving 'error: 409, reason: MinimongoError: The positional operator did not find the match needed from the query

I had to wrap the update call in a Meteor.isServer and then also use the bypassCollection2: true option to bypass SimpleSchema. It seems to be working now. Thanks

I would do it in a different way. I would keep the schema since it is there to prevent exactly these types of “go-arounds”. Since the same bar value applies to all items in the array, I wouldn’t write it to each individual item but I would keep a bar key on the document. It is then plain simple to compose that structure in the client or server side. If however you are in that situation where, for instance, bar is a user display name and you want to update that display name in all possible records if the user changes her name, I would normally use the user’s Id and pull its data with another query.

{
   _id: 'xxxxxx',
   bar: '....',
   foo: [
      {
       hasBar: true, // only write once or update individually as necessary
        somethingElse: '......'
      },
      {
        hasBar: false,
         somethingElse: '.....'
      }   
   ]
}

{ multi: true } always raises the question of serialized vs deserialized and structured vs document based. With many documents over time, multi: true may lead to bottlenecks and this is when people come back to the forum and complain how slow and non-scalable is Meteor

@paulishca Thanks for your insights. Can multi: true really be that inefficient and are you actually better off updating one Document at a time? At what amount of Documents will this make a difference? Thanks!

It depends how many users observe how many documents that are changing. The “problem” is more global (infrastructure level) than at the method level.