MongoDB: совокупные значения всех полей определенного вложенного документа

Я пытаюсь использовать совокупную структуру MongoDB для создания документов из коллекции, которая имеет следующую структуру:

{
  "_id" : ObjectId("5510eb56f877bbef153d236d"),
  "attributes" : {
    "brand" : "Mercedes",
    "price" : 289,
    "family" : "GARDEN"
  },
  "name" : "Bigger Fix Soft Crisps"
}
{
  "_id" : ObjectId("5510eb56f877bbef153d236e"),
  "attributes" : {
    "brand" : "Adelholzener",
    "price" : 683,
    "family" : "COMPUTER"
  },
  "name" : "Soft Stockhome Chips"
}
{
  "_id" : ObjectId("5510eb56f877bbef153d236f"),
  "attributes" : {
    "brand" : "Pepsi",
    "price" : 789,
    "family" : "CAR"
  },
  "name" : "Light Yearsailfresh Meat"
}

Я хочу получить агрегацию всех полей из поддокумента attributes с их возможными значениями. Поскольку поля в поддокументе неизвестны, я не могу просто использовать поля, указанные в этом примере, и поэтому должен быть динамическим. Результат должен выглядеть примерно так:

{
  "_id" : "brand",
  "values" : [
    "Mercedes", "Adelholzener", "Pepsi"
  ]
},
{
  "_id" : "price",
  "values" : [
    289, 683, 789
  ]
},
{
  "_id" : "family",
  "values" : [
    "GARDEN", "COMPUTER", "CAR"
  ]
}

Я не нашел решения до сих пор для этой конкретной проблемы. Я пробовал с $project и $unwind (что, очевидно, работает только для массивов).


person fdomig    schedule 24.04.2015    source источник
comment
можно рассказать о коллекции?   -  person Dev    schedule 24.04.2015
comment
может быть, вам следует использовать три отдельных агрегации, чтобы узнать brand, price и family, в противном случае разумно использовать уменьшение карты   -  person Yogesh    schedule 24.04.2015


Ответы (1)


Пытался выяснить, как это сделать с агрегатом, но я не уверен, что это возможно, поскольку вы не можете получить ключи в объекте любым удобным способом.

Вот задание MapReduce, которое делает это:

db.runCommand({
  "mapreduce" : "test_collection", // Change collection here
  "map" : function() {
    for (var key in this.attributes) {
      // Emit objects w array as we cannot reduce arrays directly
      emit(key, {x: [this.attributes[key]]});
    }
  },
  "reduce" : function(key, values) { 
    var res = [];
    values.forEach(function (d) {
      Array.prototype.push.apply(res, d.x);         
    });
    return {x: res};
  }, 
  "finalize": function (key, reducedVal) {
    return reducedVal.x;
  },
  "out": { inline: 1 }
});
person while    schedule 24.04.2015
comment
Это действительно работает, но, как вы сказали, вероятно, нет хорошего способа получить ключи от объекта. Благодарю вас! - person fdomig; 27.04.2015