網站首頁 編程語言 正文
MongoDB聚合管道 $lookup 與$mergeObjects配合使用 以及使用let,pipeline自定義參數進行指定多個連接條件
作者:正直的劉大炮. 更新時間: 2022-09-25 編程語言
使用$lookup
與$mergeObjects
配合使用
以及進行指定多個連接條件
語法 | 說明 |
---|---|
from | 同一個數據庫下等待被Join的集合。 |
localField | 源集合中的match值,如果輸入的集合中,某文檔沒有 localField這個Key(Field),在處理的過程中,會默認為此文檔含有 localField:null的鍵值對。 |
foreignField | 待Join的集合的match值,如果待Join的集合中,文檔沒有foreignField值,在處理的過程中,會默認為此文檔含有 foreignField:null的鍵值對 |
as | 為輸出文檔的新增值命名。如果輸入的集合中已存在該值,則會覆蓋掉 |
注意!!
$lookup是如果涉及關聯"_id",注意兩個字段的類型,用string類型匹配ObjectId類型是關聯不上的
準備數據
//訂單表
db.orders.insert([
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
{ "_id" : 3 }
])
//庫存表
db.inventory.insert([
{ "_id" : 1, "sku" : "almonds", description: "product 1", "instock" : 120 },
{ "_id" : 2, "sku" : "bread", description: "product 2", "instock" : 80 },
{ "_id" : 3, "sku" : "cashews", description: "product 3", "instock" : 60 },
{ "_id" : 4, "sku" : "pecans", description: "product 4", "instock" : 70 },
{ "_id" : 5, "sku": null, description: "Incomplete" },
{ "_id" : 6 }
])
兩種用法
1.一種關聯
{
$lookup:
{
//要關聯的從表名
from: <collection to join>,
//主表關聯字段
localField: <field from the input documents>,
//從表中與主表關聯的字段
foreignField: <field from the documents of the "from" collection>,
//別名
as: <output array field>
}
}
2.自定義多種關聯
{
$lookup:
{
//要關聯的從表名
from: <collection to join>,
//自定義變量有一個或多個變量
let: { <var_1>: <expression>, …, <var_n>: <expression> },
//自定義的操作從表的聚合但不允許使用out和merge操作
pipeline: [ <pipeline to execute on the collection to join> ],
//別名
as: <output array field>
}
}
orders表為主表 inventory表為從表 根據 orders表的item字段與inventory表的sku進行關聯
db.orders.aggregate([
{
$lookup:
{
from: "inventory",
localField: "item",
foreignField: "sku",
as: "inventory_docs"
}
}
])
該操作返回以下文檔:
// 1
{
"_id": 1,
"item": "almonds",
"price": 12,
"quantity": 2,
"inventory_docs": [
{
"_id": 1,
"sku": "almonds",
"description": "product 1",
"instock": 120
}
]
}
// 2
{
"_id": 2,
"item": "pecans",
"price": 20,
"quantity": 1,
"inventory_docs": [
{
"_id": 4,
"sku": "pecans",
"description": "product 4",
"instock": 70
}
]
}
// 3
{
"_id": 3,
"inventory_docs": [
{
"_id": 5,
"sku": null,
"description": "Incomplete"
},
{
"_id": 6
}
]
}
對應sql的寫法
SELECT *, inventory_docs
FROM orders
WHERE inventory_docs IN (SELECT *
FROM inventory
WHERE sku= orders.item);
使用lookup操作數組
準備數據
db.classes.insert([
{
_id: 1,
title: "Reading is ...",
enrollmentlist: ["giraffe2", "pandabear", "artie"],
days: ["M", "W", "F"]
},
{
_id: 2,
title: "But Writing ...",
enrollmentlist: ["giraffe1", "artie"],
days: ["T", "F"]
}
])
db.members.insert( [
{ _id: 1, name: "artie", joined: new Date("2016-05-01"), status: "A" },
{ _id: 2, name: "giraffe", joined: new Date("2017-05-01"), status: "D" },
{ _id: 3, name: "giraffe1", joined: new Date("2017-10-01"), status: "A" },
{ _id: 4, name: "panda", joined: new Date("2018-10-11"), status: "A" },
{ _id: 5, name: "pandabear", joined: new Date("2018-12-01"), status: "A" },
{ _id: 6, name: "giraffe2", joined: new Date("2018-12-01"), status: "D" }
])
classes主表 通過enrollmentlist 與members從表進行關聯
不同之處是:主表的關聯字段是數組的結構 跟從表的關聯關系時多對一的關系
db.classes.aggregate([
{
$lookup:
{
from: "members",
localField: "enrollmentlist",
foreignField: "name",
as: "enrollee_info"
}
}
])
返回的集合
// 1
{
"_id": 1,
"title": "Reading is ...",
"enrollmentlist": [
"giraffe2",
"pandabear",
"artie"
],
"days": [
"M",
"W",
"F"
],
"enrollee_info": [
{
"_id": 1,
"name": "artie",
"joined": ISODate("2016-05-01T00:00:00.000Z"),
"status": "A"
},
{
"_id": 5,
"name": "pandabear",
"joined": ISODate("2018-12-01T00:00:00.000Z"),
"status": "A"
},
{
"_id": 6,
"name": "giraffe2",
"joined": ISODate("2018-12-01T00:00:00.000Z"),
"status": "D"
}
]
}
// 2
{
"_id": 2,
"title": "But Writing ...",
"enrollmentlist": [
"giraffe1",
"artie"
],
"days": [
"T",
"F"
],
"enrollee_info": [
{
"_id": 1,
"name": "artie",
"joined": ISODate("2016-05-01T00:00:00.000Z"),
"status": "A"
},
{
"_id": 3,
"name": "giraffe1",
"joined": ISODate("2017-10-01T00:00:00.000Z"),
"status": "A"
}
]
}
使用$lookup
與$mergeObjects
配合使用
db.orders.insert([
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }
])
db.items.insert([
{ "_id" : 1, "item" : "almonds", description: "almond clusters", "instock" : 120 },
{ "_id" : 2, "item" : "bread", description: "raisin and nut bread", "instock" : 80 },
{ "_id" : 3, "item" : "pecans", description: "candied pecans", "instock" : 60 }
])
$replaceRoot:用指定的文檔替換輸入文檔。該操作將替換輸入文檔中的所有現有字段,包括_id字段。您可以將現有嵌入文檔提升到頂層,或創建新文檔進行提升
$mergeObjects:將多個文檔合并為一個文檔。
mergeObjects忽略對象{}。如果mergeObjects的所有操作數都解析為null,那么mergeObject將返回一個空文檔{}。
合并對象在合并文檔時覆蓋字段值。如果要合并的文檔包含相同的字段名,則結果文檔中的字段具有該字段最后一個合并文檔中的值。
$arrayElemAt:返回指定數組索引處的元素。
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item", //orders表的字段
foreignField: "item", // item表的字段
as: "fromItems"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: ["$fromItems", 0]
}, "$$ROOT"]
}
}
},
{
$project: {
fromItems: 0
}
}
])
該操作返回的集合
{
"_id": 1,
"item": "almonds",
"description": "almond clusters",
"instock": 120,
"price": 12,
"quantity": 2
}
{
"_id": 2,
"item": "pecans",
"description": "candied pecans",
"instock": 60,
"price": 20,
"quantity": 1
}
使用$lookup指定多個聯接條件
準備數據
db.orders.insert([
{ "_id" : 1, "item" : "almonds", "price" : 12, "ordered" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "ordered" : 1 },
{ "_id" : 3, "item" : "cookies", "price" : 10, "ordered" : 60 }
])
db.warehouses.insert([
{ "_id" : 1, "stock_item" : "almonds", warehouse: "A", "instock" : 120 },
{ "_id" : 2, "stock_item" : "pecans", warehouse: "A", "instock" : 80 },
{ "_id" : 3, "stock_item" : "almonds", warehouse: "B", "instock" : 60 },
{ "_id" : 4, "stock_item" : "cookies", warehouse: "B", "instock" : 40 },
{ "_id" : 5, "stock_item" : "cookies", warehouse: "A", "instock" : 80 }
])
注意:
pipeline中的 m a t c h 特殊操作需要 match特殊操作需要 match特殊操作需要expr進行條件過濾,如果在使用match沒有效果的的情況下可以試試$expr哦
$expr運算符僅使用from集合上的索引進行相等匹配。例如,如果倉庫集合上存在索引{stock_item:1,instock:1}:
db.orders.aggregate([
{
$lookup:
{
from: "warehouses",
let: { order_item: "$item", order_qty: "$ordered" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$stock_item", "$$order_item" ] },
{ $gte: [ "$instock", "$$order_qty" ] }
]
}
}
},
{ $project: { stock_item: 0, _id: 0 } }
],
as: "stockdata"
}
}
])
返回的集合
{
"_id": 1,
"item": "almonds",
"price": 12,
"ordered": 2,
"stockdata": [{
"warehouse": "A",
"instock": 120
}, {
"warehouse": "B",
"instock": 60
}]
}
{
"_id": 2,
"item": "pecans",
"price": 20,
"ordered": 1,
"stockdata": [{
"warehouse": "A",
"instock": 80
}]
}
{
"_id": 3,
"item": "cookies",
"price": 10,
"ordered": 60,
"stockdata": [{
"warehouse": "A",
"instock": 80
}]
}
對應sql的寫法
SELECT *, stockdata
FROM orders
WHERE stockdata IN ( SELECT warehouse, instock
FROM warehouses
WHERE stock_item = orders.item
AND instock >= orders.ordered );
允許指定多個連接條件以及不相關的子查詢。
準備數據
db.absences.insert([
{ "_id" : 1, "student" : "Ann Aardvark", sickdays: [ new Date ("2018-05-01"),new Date ("2018-08-23") ] },
{ "_id" : 2, "student" : "Zoe Zebra", sickdays: [ new Date ("2018-02-01"),new Date ("2018-05-23") ] },
])
db.holidays.insert([
{ "_id" : 1, year: 2018, name: "New Years", date: new Date("2018-01-01") },
{ "_id" : 2, year: 2018, name: "Pi Day", date: new Date("2018-03-14") },
{ "_id" : 3, year: 2018, name: "Ice Cream Day", date: new Date("2018-07-15") },
{ "_id" : 4, year: 2017, name: "New Years", date: new Date("2017-01-01") },
{ "_id" : 5, year: 2017, name: "Ice Cream Day", date: new Date("2017-07-16") }
])
db.absences.aggregate([
{
$lookup:
{
from: "holidays",
pipeline: [
{ $match: { year: 2018 } },
{ $project: { _id: 0, date: { name: "$name", date: "$date" } } },
{ $replaceRoot: { newRoot: "$date" } }
],
as: "holidays"
}
}
])
返回的集合
{
"_id": 1,
"student": "Ann Aardvark",
"sickdays": [ISODate("2018-05-01T00:00:00Z"), ISODate("2018-08-23T00:00:00Z")],
"holidays": [{
"name": "New Years",
"date": ISODate("2018-01-01T00:00:00Z")
}, {
"name": "Pi Day",
"date": ISODate("2018-03-14T00:00:00Z")
}, {
"name": "Ice Cream Day",
"date": ISODate("2018-07-15T00:00:00Z")
}]
}
{
"_id": 2,
"student": "Zoe Zebra",
"sickdays": [ISODate("2018-02-01T00:00:00Z"), ISODate("2018-05-23T00:00:00Z")],
"holidays": [{
"name": "New Years",
"date": ISODate("2018-01-01T00:00:00Z")
}, {
"name": "Pi Day",
"date": ISODate("2018-03-14T00:00:00Z")
}, {
"name": "Ice Cream Day",
"date": ISODate("2018-07-15T00:00:00Z")
}]
}
對應sql的寫法
SELECT *, holidays
FROM absences
WHERE holidays IN (SELECT name, date
FROM holidays
WHERE year = 2018);
內容來自:
mongoDB $lookup (aggregation)官方文檔版本4.2
mongoDB $mergeObjects (aggregation)官方文檔版本4.2
mongoDB $arrayElemAt (aggregation)官方文檔版本4.2
mongoDB $replaceRoot (aggregation)官方文檔版本4.2
原文鏈接:https://blog.csdn.net/qq_32492415/article/details/127032706
相關推薦
- 2022-08-30 MongoDB數據庫基礎知識整理_MongoDB
- 2022-11-30 ASP.NET?MVC實現本地化和全球化_實用技巧
- 2022-10-13 詳解python-opencv?常用函數_python
- 2022-10-17 shell腳本的流程控制語句的實現_linux shell
- 2022-05-25 C語言三個函數的模擬實現詳解_C 語言
- 2022-01-10 微信小程序報錯 Cannot read property ‘forceUpdate‘ of u
- 2021-12-04 C語言實現可排序通訊錄的示例代碼_C 語言
- 2022-04-25 Python實現實時增量數據加載工具的解決方案_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支