user2402616
user2402616

Reputation: 1563

Meteor MongoDB Setting field of array per document

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!

Upvotes: 0

Views: 98

Answers (2)

Ricardo Aragão
Ricardo Aragão

Reputation: 386

If your data have different data in the $set for each entry on array, I think you need a loop in server side.

Mongo has Bulk operations, but I don't know if you can call them using Collection.rawCollection().XXXXX
I've used rawCollection() to access aggregate and it works fine to me. Maybe work with bulk operations.

Upvotes: 1

Jordan Baker
Jordan Baker

Reputation: 4645

Try passing an option to bypass Simple Schema. It might be lacking support for this (somewhat) newer Mongo feature.

bypassCollection2

Example:

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

Old answer:

Since you say you need to make a unique update for each document it sounds like bulk updating is the way to go in this case. Here's an example of how to do this in Meteor.

if (docsToUpdate.length < 1) return
const bulk = MyCollection.rawCollection().initializeUnorderedBulkOp()
for (const myDoc of docsToUpdate) {
  bulk.find({ _id: myDoc._id }).updateOne({ $set: update })
}
Promise.await(bulk.execute()) // or use regular await if you want...

Note we exit the function early if there's no docs because bulk.execute() throws an exception if there's no operations to process.

Upvotes: 1

Related Questions