Свяжите детей с родителями, используя совокупный запрос Mongo

У меня есть одна коллекция с именем assets, которая содержит документы в 2+ форматах, ParentObject и ChildObject. В настоящее время я связываю ParentObject с ChildObject двумя запросами. Можно ли это сделать с помощью агрегированного запроса?

Родительский объект

{
    "_id" : {
        "oid" : "ParentFooABC",
        "brand" : "acme"
    },
    "type": "com.ParentClass",
    "title": "Title1234",

    "availableDate": Date,
    "expirationDate": Date
}

дочерний объект

{
    "_id" : {
        "oid" : "ChildFoo",
        "brand" : "acme"
    },
    "type": "com.ChildClass",
    "parentObject": "ParentFooABC",
    "title": "Title1234",
    "modelNumber": "8HE56",
    "modelLine": "Metro",
    "availableDate": Date,
    "expirationDate": Date,
    "IDRequired": true
}

В настоящее время я фильтрую данные следующим образом

val parent = db.asset.find(MongoDBObject("_id.brand": MongoDBObject($eq: "acme")),MongoDBObject("type":"com.ParentClass"))
val children = db.asset.find(MongoDBObject("_id.brand": MongoDBObject($eq: "acme")),MongoDBObject("type":"com.ChildClass"), MongoDBObject("parentObject": "${parent._id.oid}"))
if(childs.nonEmpty) {
  //I have confirmed this parent has a child associated and should be returned
  val childModelNumbers = childs.map(child -> child.modelNumber)
  val response = ResponseObject(parent, childModelNumbers)
}

Могу ли я сделать это в агрегированном запросе?

Обновлено:

Версия Mongo: версия БД v2.6.11

Язык: Скала

Драйвер: Casbah 2.8.1


person Kevin Harper    schedule 02.05.2016    source источник


Ответы (1)


Технически да, однако то, что вы делаете сейчас, является стандартной практикой с mongodb. Если вам нужно часто объединять наборы данных, вам, вероятно, следует использовать СУБД. Однако, если вам иногда нужно агрегировать данные из двух отдельных коллекций, тогда есть $lookup . Как правило, вы довольно часто заполняете данные в свой документ из другого документа, но обычно именно так работает база данных документов. Я бы не рекомендовал использовать $lookup, когда вы действительно ищете эквивалент SQL JOIN. На самом деле это не предполагаемая цель, и вам лучше делать именно то, что вы делаете сейчас, или переходить на РСУБД.

Добавление:

Поскольку данные находятся в одной коллекции, вы можете использовать агрегацию для $group этих данных вместе. Вам просто нужно сгруппировать их на основе _id.brand.

Быстрый пример (в оболочке mongodb):

db.asset.aggregate([
{  //start with a match to narrow down
   $match: {"_id.brand": "acme"}
},
{ //group by `_id.brand`
   $group: {
      _id: "$_id.brand",
      "parentObject": {$first: "$parentObject"},
      title: {$first: "$title"},
      modelNumer: {$addToSet: "$modelNumer"}, //accumulate child model # as array
      modelLine: {$addToSet: "$modelLine"}, //accumulate child model line as array
      availableDate: {$first: "$availableDate"},
      expirationDate: {$first: "$expirationDate"}
   }
}
]);

Это должно возвращать документы, в которых все дочерние свойства были сгруппированы в родительский документ в виде массива (modelNumber, modelLine). Вероятно, лучше сделать то, что вы делаете выше, может быть, даже лучше, если вы поместите дочерние элементы в их собственную коллекцию вместо того, чтобы отслеживать их тип с помощью поля type в документе. Таким образом, вы знаете, что документы в каждой коллекции представляют заданную структуру данных. Однако, если бы вы сделали это, вы не смогли бы выполнить агрегацию в примере.

person tsturzl    schedule 02.05.2016
comment
Спасибо за быстрый ответ! Я совершил ошибку, изначально не указав номер своей версии Mongo, и $lookup мне недоступен Документ Mongo 2.6. Хотя это выглядит так, как будто я выполняю объединение, и ParentObject, и ChildObject на самом деле находятся в одной коллекции. Я надеялся получить все документы с помощью $match, а затем сравнить их в одном и том же конвейере агрегации. - person Kevin Harper; 03.05.2016
comment
@KevinHarper Да, это было довольно недавнее дополнение. Обычно у вас будет родитель и дочерний элемент в разных коллекциях, вы сохраните идентификатор в качестве ссылки в дочернем или родительском документе, а затем запросите дочерние элементы на основе родительского идентификатора или запроса на основе массива дочерних идентификаторов, хранящихся в родительском . Я совершенно упустил момент, что они оба были в одной коллекции. Однако вы могли бы, вероятно, $group с помощью _id.brand получить любые данные, которые вам нужны, из каждого документа с вашим текущим подходом. - person tsturzl; 03.05.2016
comment
@KevinHarper Вы должны обновить свой вопрос, и я обновлю свой ответ, чтобы он соответствовал ему. Какой язык вы используете? Вероятно, было бы полезно пометить его в вашем вопросе. - person tsturzl; 03.05.2016
comment
Отличное предложение. Я обновил свой вопрос, указав версию Mongo, язык (Scala) и драйвер (Casbah). - person Kevin Harper; 04.05.2016
comment
@KevinHarper У меня нет опыта работы с casbah, однако я могу привести несколько примеров в виде запросов mongodb, а не отформатированных с помощью DSL casbah. Было бы это приемлемо? - person tsturzl; 06.05.2016