【问题标题】:How to update property in multiple objects in an array for one document in Meteor collection/minimongo?如何为 Meteor 集合/minimongo 中的一个文档更新数组中多个对象的属性?
【发布时间】:2016-09-07 17:06:54
【问题描述】:

我的问题几乎与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" : "....."
}
]}

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

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

我试过了:

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

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

【问题讨论】:

  • 你能告诉我们你到目前为止所做的尝试吗?

标签: mongodb meteor mongodb-query minimongo


【解决方案1】:

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

【讨论】:

  • 我更新了我的问题以澄清我的目标,即应用程序的真正速度和性能。实际上,对象数组的大小会实时增加(例如带有消息传递的聊天应用程序),因此我正在寻找更新文档的最佳方法,尽可能有选择性。我试过查询服务器,在客户端修改并重新更新服务器,这让我的应用程序真的很慢。
【解决方案2】:

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

服务器:

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

【讨论】:

  • 感谢您的建议。抱歉,我只需要更新我的问题以澄清我的目标,即真正的速度和性能。这是解决此问题的好方法,尽管我想知道它与查询服务器、通过数组方法在客户端处理并在服务器上更新有何不同,这对我来说可能听起来更简单。不过,我会尝试测试看看哪种票价更好。
  • 此方法有效。我已经测试过了。至于性能,我测试了另一种方法。我会比较我的答案。谢谢!
【解决方案3】:

到目前为止,我已经尝试了 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 次方法调用的测试,平均吞吐量和响应时间如下:

方法一:
平均吞吐量 - 0.08/分钟
平均响应时间 - 219ms

方法二:
平均吞吐量 - 0.12/分钟
平均响应时间 - 109ms

Chridam 的方法:
平均吞吐量 - 0.08/分钟
平均响应时间 - 221ms

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

非常感谢任何改进发布的方法或在其他情况下可能更快的 cmet。

【讨论】:

  • 谢谢。我当然希望它适用于生产。 :)
猜你喜欢
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
  • 1970-01-01
  • 2016-04-14
  • 2020-04-06
相关资源
最近更新 更多