MongoDB查詢內嵌數組(限定返回符合條件的數組中的數據)(1)


https://blog.csdn.net/bicheng4769/article/details/79579830

項目背景

最近在項目中使用mongdb來保存壓測結果中的監控數據,那么在獲取監控數據時,遇到這樣一個問題: 一個doucument中包含一個內嵌數組,其中內嵌數組也是分成好幾類的數組(可以通過標識判斷),那么我只需要返回特定的數組,而不是返回內嵌數組的所有數據。 
原始數據:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"), "addTime" : ISODate("2018-03-16T03:05:04.363Z"), "tag" : "test", "userInfo" : [ { "name" : "cj", "address" : "江蘇", "age" : 24.0, "userTag" : "stu" }, { "name" : "hj", "address" : "江蘇", "age" : 26.0, "userTag" : "stu" }, { "name" : "lbl", "address" : "美國", "age" : 22.0, "userTag" : "teach" } ] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

查詢條件是 tag =“test” userTag=”teach” 的學生的信息。期望返回的結果如下所示:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"), "userInfo" : [ { "name" : "lbl", "address" : "美國", "age" : 22.0, "userTag" : "teach" } ] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

但大多是find 的結果 是這樣的

db.test.find({"userInfo.userTag":"teach","tag":"test"}) { "_id" : ObjectId("5aab3460353df3bd352e0e15"), "addTime" : ISODate("2018-03-16T03:05:04.363Z"), "tag" : "test", "userInfo" : [ { "name" : "cj", "address" : "江蘇", "age" : 24.0, "userTag" : "stu" }, { "name" : "hj", "address" : "江蘇", "age" : 26.0, "userTag" : "stu" }, { "name" : "lbl", "address" : "美國", "age" : 22.0, "userTag" : "teach" } ] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

$elemMatch 介紹

其實我們在學習一個新的東西的時候,我建議是去官方文檔查看一下,畢竟官方的才是最權威的。官方地址: 
https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/#proj._S_elemMatch
我們可以看到 $elemMatch 是在projections方法下面,projections代表是限制返回字段的方法。 
修改后的方法:

db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch{"userTag":"teach"}}})
  • 1

執行結果

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"), "userInfo" : [ { "name" : "lbl", "address" : "美國", "age" : 22.0, "userTag" : "teach" } ] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

終於得到我想要的結果了 hhhhhhhhhhhhhhhhhhhhh。 
然后我又想獲取userInfo.userTag = “stu” 的數據,很簡單啊

db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch:{"userTag":"stu"}}})
  • 1

但是結果出人意料:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"), "userInfo" : [ { "name" : "cj", "address" : "江蘇", "age" : 24.0, "userTag" : "stu" } ] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

明明是2條stu的結果,為什么至返回一條呢? 其實$elemMatch 的定義 在官網中已經說過了,這是原話:

The $elemMatch operator limits the contents of an <array> field from the query results to contain only the first element matching the $elemMatch condition.
  • 1

注意 only the first element 也就是僅僅匹配第一個合適的元素。 
那么 對於數組中只有一個返回元素,我們可以使用$elemMatch來查詢,但是對於多個元素$elemMatch 是不適應。

$Aggregation介紹

文檔地址:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

  1. $unwind: 
    https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#pipe._S_unwind 
    大概意思就是將數組中的每一個元素轉為每一條文檔

  2. $match: 
    https://docs.mongodb.com/manual/reference/operator/aggregation/match/ 
    簡單的過濾文檔,條件查詢。

  3. $project 
    https://docs.mongodb.com/manual/reference/operator/aggregation/project/ 
    修改輸入文檔的結構

執行命令:

db.test.aggregate([{"$unwind":"$userInfo"}, {"$match":{"userInfo.userTag":"stu","tag":"test"}}, {"$project":{"userInfo":1}}])
  • 1
  • 2
  • 3

結果

/* 1 */ { "_id" : ObjectId("5aab3460353df3bd352e0e15"), "userInfo" : { "name" : "cj", "address" : "江蘇", "age" : 24.0, "userTag" : "stu" } } /* 2 */ { "_id" : ObjectId("5aab3460353df3bd352e0e15"), "userInfo" : { "name" : "hj", "address" : "江蘇", "age" : 26.0, "userTag" : "stu" } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這樣的一個結果就是我們想要的。感興趣的同學可以分別執行下這個三個操作(比較看看三個結果有什么不同),你就能理解 $unwind、$match、$project 三個方法的作用

db.test.aggregate([{"$unwind":"$userInfo"}]) db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}}]) db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}},{"$project":{"userInfo":1}}])
  • 1
  • 2
  • 3

總結

  1. 之前查詢內嵌數組時,采用的方法是將整條document查詢出來之后,在對內嵌數組進行代碼過濾。只是覺得這種查詢方式並沒有用到mongodb的其他的一些方法,還是需求驅動學習。
  2. 學習一個新的東西建議從官方文檔開始學習。

結束語:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM