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.