項目背景
最近在項目中使用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"
}
]
}
查詢條件是 tag =“test” userTag=”teach” 的學生的信息。期望返回的結果如下所示:
{
"_id" : ObjectId("5aab3460353df3bd352e0e15"),
"userInfo" : [
{
"name" : "lbl",
"address" : "美國",
"age" : 22.0,
"userTag" : "teach"
}
]
}
但大多是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"
}
]
}
$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"}}})
執行結果
{
"_id" : ObjectId("5aab3460353df3bd352e0e15"),
"userInfo" : [
{
"name" : "lbl",
"address" : "美國",
"age" : 22.0,
"userTag" : "teach"
}
]
}
終於得到我想要的結果了 hhhhhhhhhhhhhhhhhhhhh。
然後我又想獲取userInfo.userTag = “stu” 的數據,很簡單啊
db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch:{"userTag":"stu"}}})
但是結果出人意料:
{
"_id" : ObjectId("5aab3460353df3bd352e0e15"),
"userInfo" : [
{
"name" : "cj",
"address" : "江蘇",
"age" : 24.0,
"userTag" : "stu"
}
]
}
明明是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.
注意 only the first element 也就是僅僅匹配第一個合適的元素。
那麼 對於數組中只有一個返回元素,我們可以使用$elemMatch來查詢,但是對於多個元素$elemMatch 是不適應。
$Aggregation介紹
文檔地址:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
$unwind:
https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#pipe._S_unwind
大概意思就是將數組中的每一個元素轉爲每一條文檔
$match:
https://docs.mongodb.com/manual/reference/operator/aggregation/match/
簡單的過濾文檔,條件查詢。
$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 */
{
"_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"
}
}
這樣的一個結果就是我們想要的。感興趣的同學可以分別執行下這個三個操作(比較看看三個結果有什麼不同),你就能理解 $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}}])
————————————————
原文鏈接:https://blog.csdn.net/bicheng4769/article/details/79579830