2016-01-26 4 views
0

я следующий упрощенная схема:Mongoose - эффективное обновление индексированного массива mongoose.Schema.Types.Mixed

var restsSchema = new Schema({ 
    name: String 
    menu: [mongoose.Schema.Types.Mixed] 
}); 

Мой документ может выглядеть как:

{ 
    name: "Sandwiches & More", 
    menu: [ 
       {id:1,name:"Tona Sandwich",price: 10, soldCounter:0}, 
       {id:2,name:"Salami Sandwich",price: 10, soldCounter:0}, 
       {id:3,name:"Cheese Sandwich",price: 10, soldCounter:0} 
    ] 
} 

Сборник rests является индексируется:

db.rests.createIndex({ "menu.id": 1} , { unique: true }) 

Допустим, у меня есть этот массив идентификаторов [1,3] и на основании этого мне необходимо увеличить soldCounter на 1 из menu предметов с идентификаторами = 1 или 3.

Каким должен быть эффективный способ?

спасибо за помощников!

РЕДАКТИРОВАТЬ: Я использовал следующее решение:

db.model('rests').update({ _id: restid,'menu.id': {$in: ids}}, {$inc: {'menu.$.soldCounter': 1}}, {multi: true},function(err) { 
     if(err) 
      console.log("Error while updating sold counters: " + err.message); 
    }); 

, где ids является массив целых чисел с идентификаторами пунктов меню. restid - это идентификатор конкретного документа, который мы хотим изменить в коллекции.

По какой-то причине обновляется только первый идентификатор в массиве ids.

+0

Вы уже реализовали то, что считаете недостаточно эффективным? – Antoine

+0

Да, я обновил всю модель отдыха, которая довольно большая в своей неудовлетворительной форме. Я нашел остальное, используя 'find()', и в обратном вызове я искал желаемые проданные счетчики в цикле, увеличил их и сохранил модель. Неэффективен и может также вызвать некоторые проблемы с целостностью данных. – TBE

ответ

1

Кажется невозможным обновить сразу несколько поддокументов (см. this answer). Так что поиск & спасение, кажется, единственное решение.

Rest.findById(restId).then(function(rest){ 
    var menus = rest.menu.filter(function(x){ 
    return menuIds.indexOf(x.id) != -1; 
    }); 
    for (var menu of menus){ 
    menu.soldCounter++; 
    } 
    rest.save(); 
}); 

В конце концов, это единственная возможность поиска и один запрос на сохранение.

+0

Это приятное решение, но что, если у меня есть только 'restid', а не вся модель? все еще можно использовать свое решение с небольшим изменением, чтобы включить 'restid'? – TBE

+0

Ничего, я все понял :) 'db.model ('reests'). Update ({_id: restid, 'menu.id': {$ in: ids}}, {$ inc: {'menu. $ .soldCounter ': 1}}, {multi: true}) ' Спасибо за помощь! – TBE

+0

по какой-то причине, только обновленный «soldCounter» является первым «id» в данном массиве. Любая идея почему? Я обновил свой вопрос, чтобы включить мои выводы – TBE

2

Существует способ сделать несколько обновлений, вот оно: Просто убедитесь, что у вас есть индексы в массиве, который вы хотите обновить.

var update = { $inc: {} }; 
for (var i = 0; i < indexes.length; ++i) { 
    update.$inc[`menu.${indexes[i]}.soldCounter`] = 1; 
} 
Rests.update({ _id: restid }, update, function(error) { 
    // ... 
}); 
+0

Конечно, но вам нужно иметь индексы заранее. Вы должны быть абсолютно уверены, что массив не будет изменен, или у вас будут проблемы с целостностью данных. – Antoine

+0

Если вы хороший программист, то вы всегда знаете, что индексы полностью не заботятся, если массив был изменен. Все зависит от того, правильно ли вы подготовили свои данные. – TBE

+1

Что делать, если данные были изменены другим запросом, обработанным другим сервером вашей распределенной системы, между моментом, когда вы вычислили свои индексы и тот, который вы применяете для обновления? Неважно, насколько хорош программист. – Antoine

Смежные вопросы