MongoDB多集合排序的一種實現

需求

假設有三個類型有所不同的表,saleorders、careorders、repairorders,表中有storeId信息,用於關聯其所屬的門店stores表,現在有個需求是要將這三個表集中展示在一個表格中展示。

實現

以下驅動使用mongoose實現,MongoDB版本大於3.6。


var orders = Store.aggregate([
    {
        $match: {_id: storeId},
    },
    {
        $lookup: {
            from: "saleorders",
            let: {
                storeId: storeId,
            },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ['$storeId', '$$storeId'],
                        }
                    }
                }
            ],
            as:'sales'
        }
    },
    {
        $lookup: {
            from: "careorders",
            let: {
                storeId: storeId
            },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ['$storeId', '$$storeId']
                        }
                    }
                }
            
            ],
            as: 'cares'
        }
    },
    {
        $lookup: {
            from: "repairorders",
            let: {
                storeId: storeId
            },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ['$storeId', '$$storeId']
                        }
                    }
                }
            
            ],
            as: 'repairs'
        }
    },
    {
        $addFields: {
            "repairs.orderType": '1',
            "sales.orderType": '2',
            "cares.orderType": '3',
        }
    },
    {
        $project: {
            _id: 0,
            items: {
                $concatArrays: ['$repairs', '$cares', '$sales']
            }
        }
    },
    {$unwind: '$items'},
    {
        $replaceRoot: {
            newRoot: '$items'
        }
    },
    {$sort: {_id: -1 }},
])

這種實現的重點是使用一個排序集合之外的文檔來關聯這三個集合以及使用操作符$concatArrays來組合多個數組。常規的思路是,你要哪幾個集合,就用那些集合進行關聯,然後$unwind操作,但這種操作無法實現預期目的,因爲$lookup是對每個文檔進行對外關聯。上述寫法的思路是,假設幾個集合的文檔都集中在一個文檔中的三個字段上,那麼我們可以在單個集合上對數組合並排序。當然,前提第一步必須能找到一定會存在的唯一文檔來實現關聯,否則下面的步驟要不就關聯不了,要不就關聯多次,鑑於上面的操作是針對單個storeId的,所以必然能從stores集合中找到唯一的store文檔進行關聯。

當然,現實情況應該儘量避免這種方式來設計集合, 對於類型相似的文檔應該放在同一個集合中,而且這種查詢方式很可能出現聚合的中間步驟產生的數據量超過MongoDB限制(默認100M)的問題,應當使用allowDiskUse: true設置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章