幫助你進行複雜的操作,每個符號都會接受documents,並對這些document做些相應的操作,然後再將結果傳至下一個pipeline直到最後結果出現。
db.getCollection('sales').insertMany([ { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") }, { "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") }, { "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") } ]); db.sales.aggregate( [ { $project : { _id: 0, item : 1 , price : 1 } } ] ) // 只有被設置進去的字段才會顯示出來,其他列就不會被顯示。
假設一個collection裡面有數十個欄位,而我們真正需要的欄位只有一兩個,此時就可以使用project
$match
主要用於對一群檔案的篩選
$group
它的功能就是用來分組,你可以決定要依照什麼來分組。
$unwind
英文解釋就是『拆分』,他可以將陣列欄位的每一個值拆分為單獨的document
$sort
它可以根據任何欄位進行排序,是的與搜尋時的用法一樣,但是有件事要注意。
如果大量的資料要進行排序,建議在管道的第一節進行排序,因為可以用索引。
Mongodb 3.2版本 新增的聚合框架中的一种查询方式,它會在當前的collection返回的結果中新增一欄位。
官網上的說法太過文言文,簡單來說是當你想在當前的collection中新增一個欄位關連到另一個欄位,而關聯的key值存在於兩個collection中就可以用來匹配。
來看一下主要用法:
db.collection.aggregate([{ $lookup: { from: "<collection to join>", localField: "<field from the input documents>", foreignField: "<field from the documents of the from collection>", as: "<output array field>" } })
Field | Description |
---|---|
from | 從数据库中指定要执行连接的collection |
localField | 當前collection的欄位名稱 |
foreignField | 從from指定的collection裡面的欄位,如果from集合中的文档不包含foreignField,则$lookup会将值视为null以便进行匹配。 |
as | 存放結果而新增的欄位名稱 |
來看範例:
在資料庫中名為collection的order 插入資料
db.orders.insert([ { "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 }, { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }, { "_id" : 3 } ])
接下來再從inventory 中插入資料
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 } ])
使用 $lookup:
db.orders.aggregate([ { $lookup: { from: "inventory", localField: "item", foreignField: "sku", as: "inventory_docs" } } ])
返回結果
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2, "inventory_docs" : [ { "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 } ] } { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1, "inventory_docs" : [ { "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 } ] } { "_id" : 3, "inventory_docs" : [ { "_id" : 5, "sku" : null, "description" : "Incomplete" }, { "_id" : 6 } ] }
首先有兩個 collection
comment
{ "_id" : ObjectId("5ec5e48b7f7fa92fe266d246"), "content" : "测试", "reply" : [ { "content" : "回复1", "userId" : ObjectId("5ec5e4c37f7fa92fe266d27e") }, { "content" : "回复2", "userId" : ObjectId("5ec5e4ca7f7fa92fe266d285") }, { "content" : "回复3", "userId" : ObjectId("5ec5e4dd7f7fa92fe266d290") } ] }
以及 user
/* 1 */ { "_id" : ObjectId("5ec5e4c37f7fa92fe266d27e"), "name" : "u1" } /* 2 */ { "_id" : ObjectId("5ec5e4ca7f7fa92fe266d285"), "name" : "u2" } /* 3 */ { "_id" : ObjectId("5ec5e4dd7f7fa92fe266d290"), "name" : "u3" }
當需要在comment 表中 關聯到user,並輸出用戶的名稱時,我們需要用到comment的集合中的reply欄位,而這個欄位它是數組,此時我們可以先使用 unwind
將此數組拆分
db.comment.aggregate([ { $unwind: '$reply' // 首先拆分了reply这个数组 }, { $lookup: { from: 'user', // 从哪个Schema中查询 localField: 'reply.userId', // 本地关联的字段 foreignField: '_id', // user中用的关联字段 as: 'userInfo' // 查询到所有user后放入的字段名,这个是自定义的,是个数组类型。 } }, { $unwind:'$userInfo' //因为lookup 关联到的数据会返回的是数组,所以继续拆分一下(这里看个人需要) }, { // 按照_id 分组 $group:{ _id:'$_id', content:{$first:'$content'}, reply:{ $push:{ 'content':'$reply.content', 'userId':'$reply.userId', 'user':'$userInfo.name' } } } } ])
從 MongoDB 3.4 開始,如果localField是一個數組,則可以將數組元素與標量foreignField匹配,而無需$unwind階段。這部分等有時間再來實際操作實驗看看
2021/1/30 - TODO
在官方文檔中說明在$lookpup
中如果使用了pipeline(管道)是無法直接訪問文檔中的字段
這時候就需要先在 let 中進行定義,然後才能在pipeline裡進行引用。
要訪問pipeline中的let變量,請使用$expr運算符。
例如:
// order collection 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 } ]) // warehouses collection 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 } ]) 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 } ] }
TODO 待更新
$first
$sum
$subtract
$eq = (等于)
$gt > (大于)
$gte >= (大于等于)
$lt < (小于)
$lte <= (小于等于)
$ne != (不等于)
$nin !in (not in)
$$ROOT
// people collction [ { "_id" : ObjectId("5ca7a4b0219efd687462f965"), "id" : 1, "name" : "jack", "age" : 73 ,"hobby" : [ "taichi" ] } { "_id" : ObjectId("5ca7a4c4219efd687462f968"), "id" : 4, "name" : "xiaogang", "age" : 13, "hobby" : [ "Shuttlecock", "basketball", "football" ] } { "_id" : ObjectId("5ca7a4JK2K3H5JK2H4K38"), "id" : 3, "name" : "anne", "age" : 13, "hobby" : [ "pingpong", "football" ] } ]
假設我們需要尋找興趣是包含桌球或是籃球的人
db.people.find({ id : { $in : ["pingpong","basketball"] } } );
延續上面的例子,假設需求為興趣同時包含籃球和足球的人
db.people.find( { id: { $all:["basketball","football"] }})
$or
查詢多個或關係的多值
繼續之前的例子,假設需求為興趣同時包含 籃球和足球 又或者 包含 太極或者桌球的人
db.user.find({ $or: [ {id:{$all:["basketball","football"]},}, {id:{$in:["taichi","pingpong"]},} ] })
繼續之前的例子,假設需求為興趣同時包含 籃球和足球 並且 包含 太極或者桌球的人
db.user.find({ $and: [ {id:{$all:["basketball","football"]},}, {id:{$in:["taichi","pingpong"]},} ] })
2021-02-05 待更新
Todo: $push