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

时间:2016-09-05 08:46:31

标签: mongodb meteor mongodb-query minimongo

我的问题几乎与此question重复。不同之处在于我在Meteor框架/平台中使用了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" : "....."
}
]}

如何查询user中仅update'handled.visible':false to 'handled.visible':true事件数组中的所有对象?我想尽可能地将它放在一个查询中。我的目标是提高我的应用程序的性能。而不是必须获取整个对象数组,在客户端处理它们(更改对象属性)然后在服务器上重新更新,通过Mongo直接更新将是很好的。直接在服务器上更改数据也是本机反应性的,并且是有利的,但对我的应用程序来说并不是必需的。

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

我试过了:

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

这仅适用于数组中的第一个对象。但是,我想要更新处理中的所有对象,其中handle.visible为false。

3 个答案:

答案 0 :(得分:1)

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

服务器

使用

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

答案 1 :(得分:1)

Meteor目前不允许更新数组中的多个元素。必须循环遍历数组以更新返回的每个文档。

答案 2 :(得分:1)

到目前为止,我已尝试了3种方法,其中一种方法由chridam发布。

Chridam's Method

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

}

方法2 是通过替换所有条目,无论是真还是假,这是最简单和最直接的(我知道我在我的问题中已经指定只更新虚假条目但是为了性能) ,这个解决方案也提出)。

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次方法调用测试,平均吞吐量和响应时间如下:

方法1:
平均吞吐量 - .08 / min
平均响应时间 - 219ms

方法2:
平均吞吐量 - .12 / min
平均响应时间--109ms

Chridam的方法:
平均吞吐量 - .08 / min
平均响应时间 - 221ms

方法1和Chridam几乎相同。但我注意到使用方法2的UI更新速度更快,但吞吐量和响应时间仍然相当。我不确定方法2是否会更好,因为更多的方法调用已经完成。

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