2014-03-26 1 views
0

Я хочу объединить две коллекции mongodb.Inline/объединение другой коллекции в одну коллекцию

В принципе у меня есть коллекция, содержащая документы, которые ссылаются на один документ из другой коллекции. Теперь я хочу иметь это как встроенное/вложенное поле вместо отдельного документа.

Так просто привести пример:

Коллекция A:

[{ 
    "_id":"90A26C2A-4976-4EDD-850D-2ED8BEA46F9E", 
    "someValue": "foo" 
    }, 
    { 
    "_id":"5F0BB248-E628-4B8F-A2F6-FECD79B78354", 
    "someValue": "bar" 
    }] 

Коллекция B:

[{ 
    "_id":"169099A4-5EB9-4D55-8118-53D30B8A2E1A", 
    "collectionAID":"90A26C2A-4976-4EDD-850D-2ED8BEA46F9E", 
    "some":"foo", 
    "andOther":"stuff" 
    }, 
    { 
    "_id":"83B14A8B-86A8-49FF-8394-0A7F9E709C13", 
    "collectionAID":"90A26C2A-4976-4EDD-850D-2ED8BEA46F9E", 
    "some":"bar", 
    "andOther":"random" 
    }] 

Это должно привести к КОЛЛЕКЦИЯ глядя, как это:

[{ 
    "_id":"90A26C2A-4976-4EDD-850D-2ED8BEA46F9E", 
    "someValue": "foo", 
    "collectionB":[{ 
      "some":"foo", 
      "andOther":"stuff" 
      },{ 
      "some":"bar", 
      "andOther":"random" 
      }] 
    }, 
    { 
    "_id":"5F0BB248-E628-4B8F-A2F6-FECD79B78354", 
    "someValue": "bar" 
    }] 

ответ

1

Я хотел бы предложить что-то простое, как это из консоли:

db.collB.find().forEach(function(doc) { 
    var aid = doc.collectionAID; 
    if (typeof aid === 'undefined') { return; } // nothing 
    delete doc["_id"]; // remove property 
    delete doc["collectionAID"]; // remove property 
    db.collA.update({_id: aid}, /* match the ID from B */ 
     { $push : { collectionB : doc }}); 
}); 

Он обрабатывает каждый документ в collectionB, и если определено поле collectionAID, оно удаляет ненужные свойства (и collectionAID). Наконец, он обновляет соответствующий документ в collectionA с помощью оператора $push для добавления документа от B к полю collectionB. Если поле не существует, оно автоматически создается как массив с вновь вставленным документом. Если он существует как массив, он будет добавлен. (Если он существует, но не является массивом, он не будет работать). Поскольку звонок update не использует upsert, если _id в коллекции B не существует, ничего не произойдет.

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

Выполнение кода выше на ваших данных производит это:

{ "_id" : "5F0BB248-E628-4B8F-A2F6-FECD79B78354", "someValue" : "bar" } 
{ "_id" : "90A26C2A-4976-4EDD-850D-2ED8BEA46F9E", 
    "collectionB" : [ 
      { 
        "some" : "foo", 
        "andOther" : "stuff" 
      }, 
      { 
        "some" : "bar", 
        "andOther" : "random" 
      } 
    ], 
    "someValue" : "foo" 
} 
0

К сожалению, mapreduce не может создавать полные документы. https://jira.mongodb.org/browse/SERVER-2517

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

Надеюсь, вы указали «collectionAID», что должно улучшить скорость ваших запросов. Просто напишите то, что проходит через вашу коллекцию А один документ, в то время, загружая _id, а затем добавить массив из коллекции В.

+1

MapReduce будет по-прежнему быть бедным подходит для этого, как это пытается сделать сложное слияние. – WiredPrairie

0

Существует гораздо более быстрый способ, чем https://stackoverflow.com/a/22676205/1578508

Вы можете сделать это наоборот и пробежать коллекции вы хотите вставить ваши документы в (гораздо меньше казней!)

db.collA.find().forEach(function (x) { var collBs = db.collB.find({"collectionAID":x._id},{"_id":0,"collectionA":0}); x.collectionB = collBs.toArray(); db.collA.save(x); })

+0

Хотя это возможно быстрее (что было трудно сказать из ограниченной информации, которую вы предоставили), это не так надежно и не очищает данные, как это было предложено на примерах вашего вопроса. – WiredPrairie

+0

Чтобы очистить, вы можете сделать «db.collB.find ({« collectionAID »: x._id}, {" _id ": 0," collectionA ": 0})" вместо "db.collB.find ({" collectionAID ": x._id}) И" if (typeof aid === 'undefined') {return;} "может быть выполнено через" db.collA.find ("help": {"$ exists": true }) ..... – lukaswelte

+0

Я знаю, что трудно сказать по предоставленному ответу, но обычно, когда вы уменьшаете массив документов из B в один документ в A, он должен быстрее извлекать массивы документов, итерации по A вместо итерации по каждому документу в B и нажатия его на документ в A – lukaswelte