第一部分 需求與問題
1.1 數據結構
1.1.1 插入測試數據
db.hhw.insert({ results: [ { item: "a", qty: 26, tags: ["blank", "red"], dim_cm: [ 1, 10 ] }, { item: "a", qty: 27, tags: ["blank", "red"], dim_cm: [ 15, 30 ] }, { item: "a", qty: 28, tags: ["blank", "red"], dim_cm: [ 50, 70 ] }, { item: "b", qty: 27, tags: ["blank", "red"], dim_cm: [ 80, 90 ] } ] });
1.1.2 獲取數據, 在此沒有➕pretty()格式化
> db.hhw.find() { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] }, { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }
1.2 需求
需求一: 獲取到results中item的值為
a
的結果集合.
第二部分 解決問題
2.1 嘗試的方法一 -------- find子句$elemMatch
參考官網V3.4 eleMatch, 大致功能為投影操作符將限制查詢返回的數組字段的內容只包含匹配elemMatch條件
的數組元素。其實`$elemMatch專門用於查詢數組Field中元素是否滿足指定的條件。
> db.hhw.find({ results: { $elemMatch: { item: "a"}}}) #確實是全部數據 { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] }, { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }
按照官網V3.4 eleMatch的實例,一直達不到預期的效果,按照的版本是v3.4.0, 文檔參考的也是v3.4.0好奇!
解決的方法,參考了StackOverflow中, find之后的第一個參數設置為{}
, 但是得寫上.
> db.hhw.find({}, { results: { $elemMatch: { item: "a"} } }) #只返回了符合elemMatch的第一條數據 { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] } ] }
注意:
1. 數組中元素是內嵌文檔。
2. 如果多個元素匹配$elemMatch條件,操作符返回數組中第一個匹配條件的元素。
2.2 既然來了, 就操作一下$elemMatch吧
需求: 要查詢 dim_cm
中滿足至少存在
一個元素大於等於
10且小於20的
2.3 轉到第三部分
第三部分 聚合aggregate
3.1 語法以及參數
>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
>
$project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用於創建計算結果以及嵌套文檔。 $match:用於過濾數據,只輸出符合條件的文檔。$match使用MongoDB的標准查詢操作。 $limit:用來限制MongoDB聚合管道返回的文檔數。 $skip:在聚合管道中跳過指定數量的文檔,並返回余下的文檔。 $unwind:將文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值。 $group:將集合中的文檔分組,可用於統計結果。 $sort:將輸入文檔排序后輸出。 $geoNear:輸出接近某一地理位置的有序文檔。
參數太多,還是直接來上代碼
*還是原來的問題,在此使用aggregate來解決
3.2代碼如下
> db.hhw.aggregate(
{"$unwind": "$results"}, {"$match": {"results.item": "a"}}, {"$group":{ "_id":"$_id", "myResult":{ "$push": "$results" } }} ) #結果達到預期效果,三個a { "_id" : ObjectId("58b675a556341c2186667dd4"), "myResult" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] } ] }
3.3 接下來一步步拆分上邊的三條語句
3.3.1 $unwind: 將文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值。類似於遍歷,前后都有$符號
> db.hhw.aggregate({"$unwind": "$results"}) { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] } } { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] } } { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] } } { "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } }
3.3.3 $match過濾數據
3.3.4 $group將集合中的文檔分組,可用於統計結果
上邊的例子我們將所有的字段統一返回, 假如此時我們只想返回item
tags
呢?
> db.hhw.aggregate(
{"$unwind": "$results"}, {"$match": {"results.item": "a"}}, {"$group":{ "_id":"$_id", "myResult":{ "$push": {"Item": "$results.item", "tags": "$results.tags"} } }} ) { "_id" : ObjectId("58b675a556341c2186667dd4"), "myResult" : [ { "Item" : "a", "tags" : [ "blank", "red" ] }, { "Item" : "a", "tags" : [ "blank", "red" ] }, { "Item" : "a", "tags" : [ "blank", "red" ] } ] }
3.3.5 $project 限定結果集合
此時只有兩個字段(_id, results), 只顯示results
db.hhw.aggregate(
{ $project : { _id : 0 , results : 1 , }} ); { "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] }, { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }
遇到的問題
X.1 在mongoose 中aggregate中match id 時出現錯誤的解決辦法:
Product.aggregate(
{"$unwind": "$products"}, // 執行成功 {"$match": {"products.price": 9}}, // 執行失敗 {"$match": {"products._id": "58b77e509219010a6eac48ed"}}, #下邊方法成功 {"$match": {"products._id": new mongoose.Types.ObjectId('58b77e509219010a6eac48ed')}}, function(err, result){ if (err) { console.log(err); }else { res.send(result); } } );
mongoose中有兩個地方
定義了ObjectId
,mongoose.schema.Types.ObjectId
和mongoose.Types.ObjectId,在這里只有mongoose.Types.ObjectId才起作用。
作者:HowardHuang
鏈接:https://www.jianshu.com/p/968d75f40861