2015-10-19 2 views
0

I имеет следующую структуру:MongoDB - Обновление в массиве второго уровня

document: { 
    'data': { 
     'field_1': 'blabla', 
     'field_2': 'blabla++', 
     'interesting_field': [ 
      { 
       'f_1': 'abc', 
       'this_is_interesting': [ 
         { 
         'a1': 'text', 
         'a2': 'other_text' 
         }, 
         { 
         'a1': 'text 2', 
         'a2': 'text 3' 
         } 
       ] 
      }, 
      'etc': 'etc' 
     ] 
    }, 
    'somthing_boring': 'bla' 
} 

Что мне нужно сделать, это обновление всего «a2» от «this_is_interesting» из полого «interesting_field» (если они соответствуют определенным критериям).

Для обновления в массиве уровня 1, я могу сделать что-то вроде:

{ 
    '_id': new ObjectId('5621020d78946ac20a000021'), 
    'data.interesting_field' : { 
    $elemMatch : { 
     'f_1' : 'abc' 
    } 
    } 
}, 
{$set: {'data.interesting_field.$.something_to_update': 'something'}} 

Но ... кажется, я не могу использовать спичку для уровня массивов 2+. Есть идеи, как это сделать? (думал о mapReduce ... но не думаю, что я могу использовать его в запросе на обновление).

+0

Ваш документ недействителен. Является ли 'this_is_interesting' массив поддокументов? – styvane

+0

Мой плохой, фиксированный ... – zozo

ответ

2

Обычно вы делаете это с помощью позиционного оператора $, как вы отметили.

К сожалению, прямо сейчас оператор позиционирования поддерживает только один уровень соответствия для массивов.

Существует билет JIRA для вида поведения, которые вы хотите: https://jira.mongodb.org/browse/SERVER-831

Если вы хотите, чтобы иметь возможность изменить соответствующие элементы в this_is_interesting, вы должны изменить структуру ваших данных - либо придавить его, или разделить его на две коллекции.

EDIT: На самом деле, вы можете использовать MapReduce для обновления, как описано в этом ответе: https://stackoverflow.com/a/33172255/236660

Но это было бы очень, очень неэффективно. Я предлагаю вам реструктурировать ваши данные.

+0

Я знаю ... но я думал о другом решении ... что-то вроде ... нахожу поддокумент, в котором я нуждаюсь, используйте $ pull, чтобы удалить его (pull принимает еще одно условие, поэтому я ожидайте, что он сработает, затем нажмите модифицированную версию). В основном ... 2 запроса в 1. К сожалению, мне не удается заставить его работать. Примечание: Очевидный, порядок вложенных документов для меня не важен. Или ... как я сказал в вопросе, используйте карту уменьшить. Примечание 2: Является ли старый db, данные реструктуризации подразумевают рефакторинг кода, а atm - вопрос. – zozo

+0

@zozo, я добавил ссылку на ответ по аналогичному вопросу: http://stackoverflow.com/a/33172255/236660 - надеюсь, что это поможет –

+2

Это то, что я имел в виду :). Если мне удастся заставить его работать, должно быть хорошо. Я приму ответ в течение нескольких часов - может быть, более простое решение представится, если нет ... все в порядке. – zozo

1

Хорошо, предположим, что вы хотите обновить все документы в своей коллекции, где a2: 'other_text', и установить значение a2 на new_other. С фактической структурой вашего документа вам нужно будет пропустить каждый документ в вашей коллекции, а затем для каждого элемента массива interesting_field, тогда для каждого элемента массива this_is_interesting проверьте, соответствуют ли значения a2 заданным критериям, и в этом случае вы обновляете соответствующий подраздел -документ с использованием так называемых "dot notation" и "bulk" операций для максимальной эффективности. Вы должны динамически строить свой запрос, чтобы он работал.

var bulkOp = db.collection.initializeOrderedBulkOp(); 
var count = 0; 

db.collection.find({ "document.data.interesting_field.this_is_interesting.a2": 'other_text' }).forEach(function(doc) { 
    var interesting_field = doc.document.data.interesting_field; 
    var size = interesting_field.length; 
    for(var ind=0; ind < size; ind++) {  
     var this_is_interesting = doc.document.data.interesting_field[ind]['this_is_interesting'];  
     for(var ix=0; ix < this_is_interesting.length; ix++) { 
      if(this_is_interesting[ix]['a2'] === 'other_text') { 
       var updateDocument = {}; 
       updateDocument['document.data.interesting_field.' + ind + '.this_is_interesting.' + ix + '.a2'] = 'new_other';  
       bulkOp.find({'_id': doc._id}).update({ 
        '$set': updateDocument 
       });    
       count++;   
      }  
     }  
     if(count % 200 === 0) { 
      // Execute per 200 operations and re-init  
      bulkOp.execute();   
      bulkOp = db.collection.initializeOrderedBulkOp();  
     } 
    } 
}) 

// Clean up queues 

if(count > 0) { 
    bulkOp.execute(); 
} 

Но самое лучшее, что нужно сделать, это изменить ваши документы структура

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