Как создать представление для чтения из двух коллекций в mongoDB? - PullRequest
1 голос
/ 01 мая 2019

Начинается с синтаксиса mongoDB и используется в проекте.Я ищу решение, в котором я могу объединить более двух коллекций с парой условий для создания представления.

Вот моя коллекция Диапазон

 /* 1 */
    {
        "_id" : ObjectId("1"),
        "range" : {
            "start" : "00" 
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "FirstProduct",
                "type" : "First Type"
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type"
            },
            {
                "id" : "03",
                "name" : "Third Product",
                "type" : "Third Type"
            },
        ]
    }

    /* 2 */
    {
        "_id" : ObjectId("2"),
        "range" : {
            "start" : "100",
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "First Product",
                "type" : "First Type"
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type"
            }
        ]
    }

   /* 3 */
    {
        "_id" : ObjectId("3"),
        "range" : {
            "start" : "500",
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "First Product",
                "type" : "First Type"
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type"
            }
        ]
    }

ВторойКоллекция. Запас

/* 1 */
{
    "_id" : ObjectId("1"),
    "range" : {
        "start" : "00"
    },
    "products" : [ 
        {
            "id" : "01",
            "expired" : false,
            "returned" : false
        }, 
        {
            "id" : "02",
            "expired" : false,
            "returned" : false
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("02"),
    "range" : {
        "start" : "100"
    },
    "products" : [ 
        {
            "id" : "01",
            "expired" : true,
            "returned" : true
        }, 
        {
            "id" : "02",
            "expired" : true,
            "returned" : true
        }
        {
            "id" : "03",
            "expired" : true,
            "returned" : true
        }
    ]
}

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

For each range document in Range collections

    if Range.range.start = Stock.range.start 

        if Range.products.id = Stock.products.id

          copy "expired" and "returned" field from Stock for that product and 
          add to Range.product

        end if  

    end if 

    Return Range

Так что конечный результат будет примерно таким, как показано ниже.

    /* 1 */
    {
        "_id" : ObjectId("1"),
        "range" : {
            "start" : "00" 
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "FirstProduct",
                "type" : "First Type"
                "expired" : false,
                "returned" : false
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type"
                "expired" : false,
                "returned" : false
            } 
        ]
    }

    /* 2 */
    {
        "_id" : ObjectId("2"),
        "range" : {
            "start" : "100",
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "First Product",
                "type" : "First Type",
                "expired" : true,
                "returned" : true
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type",
                "expired" : true,
                "returned" : true
            }
        ]
    }


   /* 3 */
    {
        "_id" : ObjectId("3"),
        "range" : {
            "start" : "500",
        },  
        "products" : [ 
            {
                "id" : "01",
                "name" : "First Product",
                "type" : "First Type"
            }, 
            {
                "id" : "02",
                "name" : "Second Product",
                "type" : "Second Type"
            }
        ]
    }

Я начал с агрегированного конвейера этапов, но не смог получить правильные запросы.если кто-нибудь может помочь с правильным синтаксисом и правильной статистической функцией.Заранее спасибо.

1 Ответ

2 голосов
/ 01 мая 2019

Вам нужно $ lookup , чтобы объединить данные из обеих коллекций, но затем вы должны использовать $ unwind , чтобы иметь возможность сопоставлять соответствующие документы по product.id.На последнем шаге вы можете использовать $ group , чтобы получить обратно массив:

db.Range.aggregate([
    {
        $lookup: {
            from: "Stock",
            localField: "range.start",
            foreignField: "range.start",
            as: "stock"
        }
    },
    {
        $unwind: "$stock"
    },
    {
        $unwind: "$products"
    },
    {
        $unwind: "$stock.products"
    },
    {
        $match: { $expr: { $eq: [ "$products.id", "$stock.products.id" ] } }
    },
    {
        $group: {
            _id: "$_id",
            "range": { $first: "$range" },
            products: {
                $push: {
                    id: "$products.id",
                    name: "$products.name",
                    type: "$products.type",
                    expired: "$stock.products.expired",
                    returned: "$stock.products.returned"
                }
            }
        }
    }
])

EDIT: альтернативное решение, которое работает непосредственно с массивами, используя $ map и $ фильтр ниже.Недостаток заключается в том, что код менее читабелен, но хорошая его сторона заключается в том, что он должен возвращать документы, когда нет совпадения, и вы должны повысить производительность, используя этот подход

db.Range.aggregate([
    {
        $lookup: {
            from: "Stock",
            localField: "range.start",
            foreignField: "range.start",
            as: "stock"
        }
    },
    {
        $unwind: "$stock"
    },
    {
        $addFields: {
            products: {
                $map: {
                    input: "$products",
                    as: "p",
                    in: {
                        $let: {
                            vars: {
                                stockItem: {
                                    $arrayElemAt: [
                                        { $filter: { input: "$stock.products", cond: { $eq: [ "$$p.id", "$$this.id" ] } } }, 0
                                    ]
                                }
                            },
                            in: {
                                $cond: [
                                    { $eq: [ "$$stockItem", undefined ] },
                                    "$$p",
                                    {
                                        id: "$$p.id",
                                        name: "$$p.name",
                                        type: "$$p.type",
                                        expired: "$$stockItem.expired",
                                        returned: "$$stockItem.returned",
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $project: {
            stock: 0
        }
    }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...