【Node - Mongodb 】常用指令

pipeline操作符號

幫助你進行複雜的操作,每個符號都會接受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 } } ] )
// 只有被設置進去的字段才會顯示出來,其他列就不會被顯示。

$project

假設一個collection裡面有數十個欄位,而我們真正需要的欄位只有一兩個,此時就可以使用project

$match

$match 主要用於對一群檔案的篩選

$group

$group它的功能就是用來分組,你可以決定要依照什麼來分組。

$unwind

$unwind 英文解釋就是『拆分』,他可以將陣列欄位的每一個值拆分為單獨的document

$sort

$sort 它可以根據任何欄位進行排序,是的與搜尋時的用法一樣,但是有件事要注意。

如果大量的資料要進行排序,建議在管道的第一節進行排序,因為可以用索引。

$lookup

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 }
   ]
}

對數組使用$ lookup

首先有兩個 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 } ] }

pipeline表達式

TODO 待更新
$first

$sum

$subtract
$eq = (等于)

$gt > (大于)

$gte >= (大于等于)

$lt < (小于)

$lte <= (小于等于)

$ne != (不等于)

$nin !in (not in)

$$ROOT

查詢運算(邏輯)符

$in

// 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"] } } );

$all

延續上面的例子,假設需求為興趣同時包含籃球和足球的人

db.people.find( { id: { $all:["basketball","football"] }})

$or

$or查詢多個或關係的多值
繼續之前的例子,假設需求為興趣同時包含 籃球和足球 又或者 包含 太極或者桌球的人

db.user.find({
	$or: [
        {id:{$all:["basketball","football"]},},
        {id:{$in:["taichi","pingpong"]},}
    ]   
})

$and

繼續之前的例子,假設需求為興趣同時包含 籃球和足球 並且 包含 太極或者桌球的人

db.user.find({
	$and: [
        {id:{$all:["basketball","football"]},},
        {id:{$in:["taichi","pingpong"]},}
    ]   
})

2021-02-05 待更新
Todo: $push

上一篇:SharePoint中Event Handler的触发


下一篇:(转载)ubuntu创建、删除文件及文件夹,强制清空回收站方法