我收集了mongodb(3.0):
{
_id: 1,
m: [{_id:11, _t: 'type1'},
{_id:12, _t: 'type2'},
{_id:13, _t: 'type3'}]
},
{
_id: 2,
m: [{_id:21, _t: 'type1'},
{_id:22, _t: 'type21'},
{_id:23, _t: 'type3'}]
}
我想查找m个属性的文档,其中m._t包含['type1','type2']。
像这样:
{
_id: 1,
m: [{_id:11, _t: 'type1'},
{_id:12, _t: 'type2'}]
},
{
_id: 2,
m: [{_id:21, _t: 'type1'}]
}
我尝试使用$和$ elemMatch,但无法获得所需的结果。 怎么做,使用find()? 请帮帮我!谢谢!
答案 0 :(得分:1)
因为 $elemMatch
运算符会将查询结果中 m
数组字段的内容限制为仅包含 first < / strong>匹配 $elemMatch
条件的元素,以下内容仅返回带有第一个匹配元素的数组
{
"_id" : 11,
"_t" : "type1"
}
和
{
"_id" : 21,
"_t" : "type1"
}
使用 $elemMatch
投影查询:
db.collection.find(
{
"m._t": {
"$in": ["type1", "type2"]
}
},
{
"m": {
"$elemMatch": {
"_t": {
"$in": ["type1", "type2"]
}
}
}
}
)
<强>结果强>:
/* 0 */
{
"_id" : 1,
"m" : [
{
"_id" : 11,
"_t" : "type1"
}
]
}
/* 1 */
{
"_id" : 2,
"m" : [
{
"_id" : 21,
"_t" : "type1"
}
]
}
您可以采取的一种方法是 aggregation framework ,其中您的管道包含 $match
运算符,类似于上面的查找查询过滤初始文档流。下一个管道步骤将是关键的 $unwind
运算符,它将数组元素“拆分”,以便与另一个 $match
运算符进一步简化,然后最终 $group
管道,使用累加器运算符 $push
恢复原始数据结构。
以下说明了这条道路:
db.collection.aggregate([
{
"$match": {
"m._t": {
"$in": ["type1", "type2"]
}
}
},
{
"$unwind": "$m"
},
{
"$match": {
"m._t": {
"$in": ["type1", "type2"]
}
}
},
{
"$group": {
"_id": "$_id",
"m": {
"$push": "$m"
}
}
}
])
示例输出:
/* 0 */
{
"result" : [
{
"_id" : 2,
"m" : [
{
"_id" : 21,
"_t" : "type1"
}
]
},
{
"_id" : 1,
"m" : [
{
"_id" : 11,
"_t" : "type1"
},
{
"_id" : 12,
"_t" : "type2"
}
]
}
],
"ok" : 1
}
答案 1 :(得分:1)
让你的&#34;过滤&#34;结果,带有聚合管道的$redact
是最快的方法:
db.junk.aggregate([
{ "$match": { "m._t": { "$in": ["type1", "type2"] } } },
{ "$redact": {
"$cond": {
"if": {
"$or": [
{ "$eq": [ { "$ifNull": ["$_t", "type1"] }, "type1" ] },
{ "$eq": [ { "$ifNull": ["$_t", "type2"] }, "type2" ] }
],
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
$redact
运算符为文档设置逻辑过滤器,该过滤器也可以遍历数组级别。请注意,这在文档的所有级别上都匹配_t
,因此请确保没有其他元素共享此名称。
查询使用$in
进行选择,就像逻辑过滤器使用$or
一样。任何不匹配的东西都会得到修剪&#34;。
{
"_id" : 1,
"m" : [
{
"_id" : 11,
"_t" : "type1"
},
{
"_id" : 12,
"_t" : "type2"
}
]
}
{
"_id" : 2,
"m" : [ { "_id" : 21, "_t" : "type1" } ]
}
简短而又简单。
稍微麻烦一点,但使用$map
和$setDifference
这个结构过滤结果会更合理一些:
db.junk.aggregate([
{ "$match": { "m._t": { "$in": ["type1", "type2"] } } },
{ "$project": {
"m": {
"$setDifference": [
{ "$map": {
"input": "$m",
"as": "el",
"in": {
"$cond": {
"if": {
"$or": [
{ "$eq": [ "$$el._t", "type1" ] },
{ "$eq": [ "$$el._t", "type2" ] }
]
},
"then": "$$el",
"else": false
}
}
}},
[false]
]
}
}}
])
$map
评估每个元素的条件,$setDifference
删除任何返回false
而不是数组内容的条件。与上面的编辑中的$cond
非常相似,但它只是专门用于一个数组,而不是整个文档。
在未来的MongoDB版本中(目前在开发版本中可用),将有$filter
运算符,这非常容易理解:
db.junk.aggregate([
{ "$match": { "m._t": { "$in": ["type1", "type2"] } } },
{ "$project": {
"m": {
"$filter": {
"input": "$m",
"as": "el",
"cond": {
"$or": [
{ "$eq": [ "$$el._t", "type1" ] },
{ "$eq": [ "$$el._t", "type2" ] }
]
}
}
}
}}
])
这将删除任何与指定条件不匹配的数组元素。
如果要在服务器上过滤数组内容,则可以使用聚合框架。