How to update property in multiple objects in an array for one document in Meteor collection/minimongo?

自古美人都是妖i 提交于 2019-12-05 22:18:39

You could create a server method that uses the aggregation framework to return a count that you can use in your client as a loop to update each matching array element. The following untested example may have some pointers on how you can go about it (I haven't tested it so feedback on your implementation is much welcome to make this a better solution):

Server:

Add the meteorhacks:aggregate package to your app with

meteor add meteorhacks:aggregate

and then use as

Meteor.methods({
    getInvisibleEventsCount: function(userId){
        var pipeline = [
            { "$match": { "_id": userId, "events.handled.visible": false } },
            { "$unwind": "$events.handled" },
            { "$match": { "events.handled.visible": false } },
            { "$group": {
                "_id": null,
                "count": { "$sum": 1 }
            }}
        ];
        var result = Meteor.users.aggregate(pipeline);
        return result;
    }
});

Client:

Meteor.call("getInvisibleEventsCount", userId, function(err, response) {
    var max = response[0].count;
    while(max--) {
        Meteor.users.update(
            { "_id": userId, "events.handled.visible": false }, 
            { "$set": { "events.$.handled.visible": true} }
        );      
    }
});

Meteor currently does not allow to update multiple elements in an array. One has to loop through the array to update for each document returned.

saejuro

I have tried 3 methods so far, one as posted by chridam which works.

Chridam's Method

Method 1 just processes it in the client but selectively chooses only false entries:

testLocalAggregate : function(){
var findQuery = Meteor.users.findOne(Meteor.userId(), {fields:{'events':1}}).events;
var tempArr = [];

_.each(findQuery, function(event, index){
  if(events.handled.visible === false){
    tempArr.push(index);
  }
});


if(tempArr.length){

  var count = tempArr.length;

  while(count --){
    Meteor.users.update(
      { "_id": Meteor.userId(), "events.handled.visible": false },
      {$set:{'events.$.handled.visible':true}}
    );
  }
}

}

Method 2 is by replacing all entries regardless whether true or false, which is the simplest and most straightforward (I know I have specified in my question to only update false entries but for the sake of performance, this solution is also presented).

testUpdate : function(){
var events = Meteor.users.findOne(Meteor.userId(), {fields:{'events':1}}).events;

_.each(events, function(event, index){
  if(events.handled.visible === false){
    events.handled.visible = true;
  }
});

Meteor.users.update({_id : Meteor.userId()}, {$set: {'events': events}});

}

As per testing in Kadira with 5 method calls, the average throughputs and response times are as follows:

Method 1:
Average throughput - .08/min
Average response time - 219ms

Method 2:
Average throughput - .12/min
Average response time - 109ms

Chridam's Method:
Average throughput - .08/min
Average response time - 221ms

Method 1 and Chridam's are almost the same. But I noticed that the UI updates are faster using method 2, with still comparable throughput and response time. I'm just not sure if method 2 will be better as more method calls are done.

Any comments to improve the posted methods or which may be faster in other circumstances will be very much appreciated.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!