需求
假設有三個類型有所不同的表,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
設置。