2014-04-06 1 views
2

У меня есть коллекция структура, как так:

albums: { 
    2oBkjqYFwf3vrgDj4: { 
     _id: "2oBkjqYFwf3vrgDj4", 
     titles: [ 
      { 
       titleText: "i am an album" 
      }, 
      { 
       titleText: "this is my other title" 
      } 
     ] 
    } 
} 

Я хочу сделать что-то вроде ниже, чтобы обновить, где TitleText равно что-то, а затем изменить его:

db.albums.update({"_id": "2oBkjqYFwf3vrgDj4", "titles": {$elemMatch: {"titleText": "i am an album"}}}, 
    {$set: { 
     "titles.titleText": "i am not an album" 
    } 
) 

Я знаю, что я мог бы сделайте foreach, но это кажется большим количеством потраченных впустую ресурсов, поскольку я планирую иметь индекс на titles.titleText.

Есть ли что-то, что мне не хватает, или нет простого способа сделать это? Я использую Meteor, но я не думаю, что это должно изменить любую логику, если есть способ сделать это в MongoDB.

Спасибо всем!

+0

Возможный дубликат [Обновить поддокумент, содержащийся в массиве, содержащемся в документе MongoDB] (http://stackoverflow.com/questions/13777097/update-an-subdocument-contained-in-an-array-contained-in -a-mongodb-document) – 1615903

ответ

5

Оказывается, мой вопрос является репост из link

Эта проблема может быть решена в MongoDB, делая,

db.albums.update({ 
     "_id": "2oBkjqYFwf3vrgDj4", 
     "titles.titleText": "i am an album" 
    }, 
    {$set: 
     {"titles.$.titleText": "i am not an album"} 
    } 
) 

Когда предыдущий вопрос был размещен позиционное оператор wasn't supported by minimongo. На данный момент селектора mongo не могут использоваться из кода на стороне клиента, для security reasons.

Вышеупомянутый метод должен вызываться из Meteor.method() на сервере.

0

С помощью коллекции метеоритов api вы можете использовать update. documentation here. Вы предоставляете селектор, а затем модификатор. Вы также можете сделать то же самое непосредственно с монго. Общий синтаксис ниже, но я не запускал его сам. Я не знаю, существует ли более удобный способ, похожий на ваш код, который, возможно, DRY'er, но должен выполнить эту работу.

Albums.update(
    {_id: "2oBkjqYFwf3vrgDj4", "titles.titleText": "i am an album"}, 
    {$set:{"titles.titleText": "i am not an album"}} 
}; 
+0

Это работает, но вам нужно знать индекс для того, чтобы '$ set' работал. Поэтому мне пришлось бы делать '{$ set: {" titles.0.titleText ":« Я не альбом »}}', но это означало бы, что мне нужно получить индекс, прежде чем я смогу его обновить. Надеюсь, кто-то знает более простой способ. – Jordan

+0

Я думаю, вам понадобится несколько js, чтобы найти индекс, или вам нужно будет структурировать свой db по-другому: есть коллекция для альбомов и коллекция для названий. У вас есть ссылка на идентификаторы другого и makeIndex() для быстрой перекрестной ссылки, если это необходимо. Я сомневаюсь, что это решение, которое вы решите предпринять, но я думаю, что это единственный, который существует с учетом параметров без дополнительных js. Вам нужно будет подумать, как часто вы будете принимать это действие и сколько времени это займет. Я был бы счастлив, если бы оказался ошибочным! – Shwaydogg

+0

Да, я знал, что кто-то порекомендует реструктуризацию, но это, безусловно, самый быстрый способ для меня структурировать с точки зрения запросов. Я бы нормализовался так, что мне не нужно, просто потому, что нет простого способа обновить поддокумент. – Jordan

0

$ set не работает хорошо на стороне клиента. Приятная работа вокруг (пример его на вечеринках).

step 1: get the array for your items. 
    var album = albums.findOne().services; 
step 2: lets find the index we want using _indexOf and _pluck 
       var indexToUpdate = _.indexOf(_.pluck('insert your array', 'insert your column name'), 'insert the one you want to update'); 

       var modifier = { $set: {} }; 
       modifier.$set["services." + indexToUpdate + ".youfieldinarray"] = 'your new value'. 
step 3: update your item object  
albumns.update(Business.findOne()._id, modifier); 

Не уверен, что я сделал бы это в огромных коллекциях, но для мелких клиентов клиентов это хорошо работает.