如何在 Meteor collection/minimongo 中为一个文档更新数组中多个对象中的 属性?

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

我的问题几乎与这个 重复。区别在于我在 Meteor framework/platform 中使用 minimongo。鉴于这份文件:

{
"_id" : ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id" : "714638ba-2e08-2168-2b99-00002f3d43c0",
"events" : [
{
    "handled" : {
        "name": "Mike",
        "visible": false
    },
    "profile" : 10,
    "data" : "....."
}
{
    "handled" : {
        "name": "Shaun",
        "visible": false
    },
    "profile" : 10,
    "data" : "....."
}
{
    "handled" : {
        "name": "Glen",
        "visible": true
    },
    "profile" : 20,
    "data" : "....."
}
]}

如何仅在 'handled.visible':false to 'handled.visible':true 处查询特定 userupdate 事件数组中的所有对象?我希望尽可能将其包含在单个查询中。我的 objective 确实是为了提高我的应用程序的性能。不必获取整个对象数组,在客户端处理它们(更改对象属性)然后在服务器上重新更新,直接通过 Mongo 更新会很棒。直接在服务器上更改数据也是本机响应式的并且是有利的,尽管对于我的应用程序来说并不是必需的。

我不太确定如何在 minimongo 中制定查询。

我试过:

Meteor.users.update({_id: 's8Ppj4ZFSeq9X6xC4', 'events.handled.visible': false }, { $set:{'events.$.handled.visible':true} });

这仅适用于数组中找到的第一个对象。但是我想更新数组中 handled.visible 为假的所有对象。

您可以创建一个使用聚合框架的服务器方法来 return 您可以在客户端中使用的计数作为循环来更新每个匹配的数组元素。以下未经测试的示例可能对 你如何去做(我还没有测试过,所以非常欢迎你对你的实施提出反馈,使它成为一个更好的解决方案):

服务器:

使用

meteorhacks:aggregate 包添加到您的应用
meteor add meteorhacks:aggregate

然后用作

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;
    }
});

客户端:

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 目前不允许更新数组中的多个元素。必须遍历数组以更新返回的每个文档。

到目前为止,我已经尝试了 3 种方法,chridam 发布的一种有效。

方法 1 只是在客户端处理它,但有选择地只选择错误条目:

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}}
    );
  }
}

}

方法二是替换所有条目,不管真假,最简单直接(我知道我在问题中指定只更新错误的条目但是为了性能,也提出了这个解决方案)。

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}});

}

根据 Kadira 中 5 个方法调用的测试,平均吞吐量和响应时间如下:

方法一:
平均吞吐量 - .08/分钟
平均响应时间 - 219 毫秒

方法二:
平均吞吐量 - .12/分钟
平均响应时间 - 109 毫秒

Chridam 的方法:
平均吞吐量 - .08/分钟
平均响应时间 - 221 毫秒

方法一和Chridam的差不多。但我注意到 UI 使用方法 2 的更新速度更快,吞吐量和响应时间仍然相当。我只是不确定随着更多方法调用的完成,方法 2 是否会更好。

任何改进已发布方法或在其他情况下可能更快的方法的评论将不胜感激。