简体   繁体   中英

Meteor - How to update a document in an array

I have a document in an array and try to update a value in the document.

It is already working in Meteor's Mongo shell:

$ meteor mongo
meteor:PRIMARY> db.mycollection.update({name:"test", "foo.name":"bar"}, {$set: {"foo.$.price":42}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

But t's not working when I try to do it in Meteor with:

MyCollection.update(
    {name:"test", "foo.name":"bar"},
    {$set: {"foo.$.price":42}}
);

As you can see here: http://meteorpad.com/pad/jjazD3jYYeY7R9Bpv/DocumentArrayUpdate

This is caused because you cannot put a selector different than the Id on the client side (with autopublish/insecure):

Error: Not permitted. Untrusted code may only update documents by ID. [403]

This is where I'm lost. I have to run this update code on the server but the only examples I've seen so far are only doing some .find() or .findOne() on the server's Meteor.publish() and then all the update logic is done in Meteor.methods() which is client and server side, so in my case I cannot do that.

How can I make this work?

Edit: I've been little bit fast saying that: Meteor.methods() is both client and server side, so in my case I cannot do that . It actually works well with Meteor.methods() , I still don't know why, I think it's coming from how Meteor's Optimistic UI feature works...

Error: Not permitted. Untrusted code may only update documents by ID. [403]

This means you've removed the insecure package, which is a good thing for production. But what that means is you can no longer update your database entries from the client unless you update by the collection's ID (as the error states.

So you have two options.

First - the bad option. From the client:

MyCollection.update(
    {_id:"19283yhakjsdo23", "foo.name":"bar"},
    {$set: {"foo.$.price":42}}
);

It's not terribly bad, but it's not good either.

The good option: from the server.

Meteor has something called server side methods (a good blog post about this is available) . Server side methods are great and will allow you to do exactly what you want to do with almost the exact same code, but from the server.

So in a file called methods.js from your server directory you would write:

Meteor.methods({
    priceUpdateMethod(name, collectionkey, updateValue) {
        MyCollection.update(
            {name:name, "foo.name":"bar"},
            {$set: {collectionkey: updateValue}}
        );
    }
});

Then in your client directory you'll have a helper or something like that with a function:

Meteor.call('priceUpdateMethod',"test","foo.$.price",42)

Server is trusted. Client is untrusted.

Change your meteor method to this:

if (Meteor.isServer()) {
  MyCollection.update(
    {name:"test", "foo.name":"bar"},
    {$set: {"foo.$.price":42}}
  );
}
if (Meteor.isClient()) {
  _id = MyCollection.findOne(
    {name:"test", "foo.name":"bar"}
  )._id;
  MyCollection.update(_id, {$set: {"foo.$.price":42}});
}

As David mentioned in the comments your code will work on the server. To enable it to work on the client as well (latency compression), try this approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM