Как обновить свойство в нескольких объектах в массиве для одного документа в коллекции Meteor /minimongo?

Мой вопрос почти дубликат этого вопроса. Разница в том, что я использую минимонго в рамках / платформе Meteor. Учитывая этот документ:

{
"_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. Изменение данных непосредственно на сервере также является изначально реагирующим и выгодным, хотя на самом деле не является необходимым для моего приложения.

Я не совсем уверен, как сформулировать запрос в минимонго.

Я пытался:

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

Это работало только для первого объекта, найденного в массиве. Однако я хотел бы обновить все объекты в массиве, где handled.visible имеет значение false.

3 ответа

Решение

Вы можете создать метод сервера, который использует структуру агрегации для возврата счетчика, который вы можете использовать в своем клиенте в качестве цикла для обновления каждого соответствующего элемента массива. В следующем непроверенном примере могут быть некоторые указания о том, как вы можете это сделать (я не проверял это, поэтому отзывы о вашей реализации приветствуются, чтобы сделать это лучшим решением):

Сервер:

Добавьте пакет meteorhacks: агрегат в ваше приложение с

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 метода, один из которых опубликован 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}}
    );
  }
}

}

Метод 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/ мин
Среднее время отклика - 219 мс

Способ 2:
Средняя пропускная способность - .12/ мин
Среднее время отклика - 109мс

Метод Chridam:
Средняя пропускная способность - .08/ мин
Среднее время отклика - 221 мс

Способ 1 и Chridam's почти одинаковы. Но я заметил, что обновления пользовательского интерфейса быстрее, используя метод 2, с сопоставимой пропускной способностью и временем отклика. Я просто не уверен, что метод 2 будет лучше, так как выполняется больше вызовов метода.

Будем очень благодарны за любые комментарии по улучшению опубликованных методов или которые могут быть быстрее в других обстоятельствах.

Другие вопросы по тегам