Совокупный документ многоуровневый - PullRequest
0 голосов
/ 05 июня 2018

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

{

        "_id" : ObjectId("5788fcd1d8159c2366dd5d93"), 
        "color" : "Blue", 
        "code" : "1", 
        "category_id" : ObjectId("5693d170a2191f9020b8c815"), 
        "description" : "julia tried", 
        "name" : "Order1", 
        "brand_id" : ObjectId("5b0e52f058b8287a446f9f05")

}

Также есть коллекция для бренда и категории.Это коллекция категорий

{ 
"_id" : ObjectId("5693d170a2191f9020b8c815"), 
"name" : "Category1", 
"created_at" : ISODate("2016-01-11T20:32:17.832+0000"), 
"updated_at" : ISODate("2016-01-11T20:32:17.832+0000"), 
}

Коллекция брендов

{ 
   "_id" : ObjectId("5b0e52f058b8287a446f9f05"), 
   "name" : "brand1", 
   "description" : "brand1", 
   "updated_at" : ISODate("2017-07-05T09:18:13.951+0000"), 
   "created_at" : ISODate("2017-07-05T09:18:13.951+0000"), 
}

Теперь после применения агрегации это должно привести к следующемуформат:

{
    'brands': [
             {
                _id: '*******'
                name: 'brand1',

                categories: [
                   {
                      _id: '*****',
                      name: 'category_name1',
                      orders: [
                          {
                              _id: '*****',
                              title: 'order1'
                          }

                      ]

                   }
                ]
             }
     ]
}

1 Ответ

0 голосов
/ 05 июня 2018

Вы можете попробовать агрегацию ниже:

db.brand.aggregate([
    {
        $lookup: {
            from: "order",
            localField: "_id",
            foreignField: "brand_id",
            as: "orders"
        }
    },
    {
        $unwind: "$orders"
    },
    {
        $lookup: {
            from: "category",
            localField: "orders.category_id",
            foreignField: "_id",
            as: "categories"
        }
    },
    {
        $unwind: "$categories"
    },
    {
        $group: {
            _id: "$_id",
            name: { $first: "$name" },
            description: { $first: "$description" },
            updated_at: { $first: "$updated_at" },
            created_at: { $first: "$created_at" },
            categories: { $addToSet: "$categories" },
            orders: { $addToSet: "$orders" }
        }
    },
    {
        $addFields: {
            categories: {
                $map: {
                    input: "$categories",
                    as: "category",
                    in: {
                        $mergeObjects: [ 
                            "$$category", { 
                                orders: [ { 
                                    $filter: { 
                                        input: "$orders", 
                                        as: "order", 
                                        cond: { $eq: [ "$$category._id", "$$order.category_id" ] } 
                                    } 
                                } ]
                         } ]
                    }
                }
            }
        }
    },
    {
        $project: {
            orders: 0
        }
    }
])

Обычно вам нужно использовать $ lookup дважды, чтобы "объединить" данные из всех этих коллекций на основе brand_id и category_idполя.Поскольку вы ожидаете orders в categories в brands, вы можете использовать $ unwind для обоих массивов, а затем использовать $ group , чтобы получить следующую форму:

{
    "_id" : ObjectId("5b0e52f058b8287a446f9f05"),
    "name" : "brand1",
    "description" : "brand1",
    "updated_at" : ISODate("2017-07-05T09:18:13.951Z"),
    "created_at" : ISODate("2017-07-05T09:18:13.951Z"),
    "categories" : [
            {
                    "_id" : ObjectId("5693d170a2191f9020b8c814"),
                    "name" : "Category1",
                    "created_at" : ISODate("2016-01-11T20:32:17.832Z"),
                    "updated_at" : ISODate("2016-01-11T20:32:17.832Z")
            }
    ],
    "orders" : [
            {
                    "_id" : ObjectId("5788fcd1d8159c2366dd5d93"),
                    "color" : "Blue",
                    "code" : "1",
                    "category_id" : ObjectId("5693d170a2191f9020b8c814"),
                    "description" : "julia tried",
                    "name" : "Order1",
                    "brand_id" : ObjectId("5b0e52f058b8287a446f9f05")
            }
    ]
}

Теперь у вас есть brand1 со всеми его подкатегориями и всеми заказами, которые должны быть размещены в одной из этих категорий.Единственное, как «вложить» orders в categories.Один из способов сделать это может быть $ map , где вы можете объединить каждую категорию со всеми заказами, которые соответствуют этой категории (используя $ mergeObjects , вам не нужно указывать все свойства из объекта категорий).

Чтобы сопоставить category с orders, вы можете выполнить $ filter для orders массива.

Затем вы можете отбросить orders, поскольку они вложены вкатегории, поэтому они вам больше не нужны.

РЕДАКТИРОВАТЬ: версия 3.4

В MongoDB 3.4 вы не можете использовать $mergeObjects, поэтому вы должны указать все свойства для категорий:

db.brand.aggregate([
    {
        $lookup: {
            from: "order",
            localField: "_id",
            foreignField: "brand_id",
            as: "orders"
        }
    },
    {
        $unwind: "$orders"
    },
    {
        $lookup: {
            from: "category",
            localField: "orders.category_id",
            foreignField: "_id",
            as: "categories"
        }
    },
    {
        $unwind: "$categories"
    },
    {
        $group: {
            _id: "$_id",
            name: { $first: "$name" },
            description: { $first: "$description" },
            updated_at: { $first: "$updated_at" },
            created_at: { $first: "$created_at" },
            categories: { $addToSet: "$categories" },
            orders: { $addToSet: "$orders" }
        }
    },
    {
        $addFields: {
            categories: {
                $map: {
                    input: "$categories",
                    as: "category",
                    in: {
                        _id: "$$category._id",
                        name: "$$category.name",
                        created_at: "$$category.created_at",
                        updated_at: "$$category.updated_at",
                        orders: [ 
                            { 
                                $filter: { 
                                    input: "$orders", 
                                    as: "order", 
                                    cond: { $eq: [ "$$category._id", "$$order.category_id" ] } 
                                } 
                            } 
                        ]
                    }
                }
            }
        }
    },
    {
        $project: {
            orders: 0
        }
    }
])
...