最近在项目中使用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"
}
]
}
其实我们在学习一个新的东西的时候,我建议是去官方文档查看一下,毕竟官方的才是最权威的。官方地址:
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 field from the query results to contain only the first element matching the $elemMatch condition.
注意 only the first element 也就是仅仅匹配第一个合适的元素。
那么 对于数组中只有一个返回元素,我们可以使用$elemMatch来查询,但是对于多个元素$elemMatch 是不适应。
文档地址: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/
简单的过滤文档,条件查询。
执行命令:
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}}])
下一篇开始介绍在spring中如何查询mongdb。