2015-12-23 3 views
3

Возможно ли без ввода всех полей поддокумента?

Скажем, я иметь следующую структуру документа:

{ 
    field1: a, 
    subdoc: { 
      field2: b, 
      field3: c 
    } 
} 

Я хочу использовать $project для того, чтобы получить suboc на корневом уровне:

{ 
    field1: a, 
    field2: b, 
    field3: c    
} 

Это просто пример с 2 поля в subdoc, у моего реального документа есть много полей, и в будущем может быть добавлено или удалено больше, поэтому я хочу, чтобы $project был больше динамическим и не указывать все поля отдельно.

+0

Вы должны были бы используйте Map-Reduce сначала, чтобы получить ключи для поддокумента, затем постройте документ '$ project', используя динамически возвращаемые ключи. – chridam

+0

@chridam вы можете привести пример для схемы выше? – TomG

+0

Я привел пример в ответе ниже. – chridam

ответ

3

Вам потребуется механизм, чтобы получить все динамические ключи, которые вам необходимо собрать динамический $project документ. Это возможно через Map-Reduce. Следующая операция MapReduce будет заполнять отдельную коллекцию со всеми ключами как _id значения:

mr = db.runCommand({ 
    "mapreduce": "my_collection", 
    "map" : function() { 
     for (var key in this.subdoc) { emit(key, null); } 
    }, 
    "reduce" : function(key, stuff) { return null; }, 
    "out": "my_collection" + "_keys" 
}) 

Чтобы получить список всех динамических ключей, запустите отличие от полученной коллекции:

db[mr.result].distinct("_id") 
["field2", "field3", ...] 

сейчас учитывая приведенный выше список, вы можете собрать свой документ конвейера агрегации, создав объект, который будет иметь свои свойства, заданные в цикле. Обычно ваш $project документ будет иметь такую ​​структуру:

var project = { 
    "$project": { 
     "field1": 1, 
     "field2": "$subdoc.field2", 
     "field3": "$subdoc.field3" 
    } 
}; 

Таким образом, используя приведенный выше список ключей поддокументе, вы можете динамически построить выше, используя reduce() метод в JavaScript:

var subdocKeys = db[mr.result].distinct("_id"), 
    obj = subdocKeys.reduce(function (o, v){ 
     o[v] = "$subdoc." + v; 
     return o; 
    }, { "field1": 1 }), 
    project = { "$project": obj }; 

db.collection.aggregate([project]); 
Смежные вопросы