MongoDB如何获取子文档的不同列表,其中包含子文档';属性是否等于某个值?

MongoDB如何获取子文档的不同列表,其中包含子文档';属性是否等于某个值?,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,如何获得foo的不同列表,其中foo.type等于bar 我想找到: db.test.insert( { 'name': 'outer', 'foos': [ { 'name': 'a', 'type': 'bar', }, { 'name': 'a', '

如何获得
foo
的不同列表,其中
foo.type
等于
bar

我想找到:

db.test.insert( 
    {
        'name': 'outer',
        'foos': [
            {
                'name': 'a',
                'type': 'bar',
            },
            {
                'name': 'a',
                'type': 'bar',
            },
            {
                'name': 'z',
                'type': 'baz',
            },
            {
                'name': 'z',
                'type': 'baz',
            },
        ]
    }
)
以下操作不起作用,而是为所有foo返回一个不同的值

[
    {
        'name': 'a',
        'type': 'bar'
    }
]

是的,哎呀!对这里的函数有点误解。下面是它返回的内容,我将解释原因:

[
{
“姓名”:“a”,
“类型”:“条”
},
{
“名称”:“z”,
“类型”:“baz”
}
]
因此,另一个条目是“type”等于“baz”,现在两者都是“distinct”,但你没有回答真正的问题

您确实要求使用不同的“foos”,这是正确的。但您也只要求从“documents”中获取,该“documents”的数组条目“type”等于“bar”。这不会将内容仅“过滤”到那些数组条目,因此您会得到另一个结果

因此,在获得“不同”值之前,需要“过滤”内容。只有使用
.aggregate()
方法才能真正做到这一点。这是最好的方法:

db.test.aggregate([
//匹配文档
{“$match”:{“foos.type”:“bar”},
//对阵列进行预过滤
{“$project”:{
“foos”:{
“$filter”:{
“输入”:“$foos”,
“as”:“el”,
“条件”:{
“$eq”:[“$$el.type”,“bar”]
}
}
}
}},
//展开阵列
{“$unwind”:“$foos”},
//组独立
{“$组”:{
“\u id”:“$foos”
}}
])
或者在比MongoDB 3.2更旧但版本2.6及更高版本中,您可以交替使用:

db.test.aggregate([
//匹配文档
{“$match”:{“foos.type”:“bar”},
//对阵列进行预过滤
{“$project”:{
“foos”:{
“$setDifference”:[
{“$map”:{
“输入”:“$foos”,
“as”:“el”,
“在”:{
“$cond”:[
{“$eq”:[“$$el.type”,“bar”]},
“$$el”,
假的
]
}
}}
]
}
}},
//展开阵列
{“$unwind”:“$foos”},
//组独立
{“$组”:{
“\u id”:“$foos”
}}
])
这与
$map
处理每个数组元素并返回匹配的元素或
false
$setDiffernce
删除
false
元素是一样的:

最后,在任何早于2.6的版本中:

db.test.aggregate([
//匹配文档
{“$match”:{“foos.type”:“bar”},
//展开阵列
{“$unwind”:“$foos”},
//对非规范化数组进行滤波
{“$match”:{“foos.type”:“bar”},
//组独立
{“$组”:{
“\u id”:“$foos”
}}
])
一般原则是只保留匹配“type”等于“bar”的数组项,理想情况是在使用之前对数组进行“预筛选”,以减少需要处理的工作量,因为之后的筛选基本上会为每个数组项创建一个新文档,无论它是否匹配

无论如何,在某些时候,您需要使用
$unwind
对数组项进行“反规范化”,然后使用“foos”(子文档)作为主键值返回

这不是一个简单的“数组”,如“代码>”。“区别”(<)/代码>传递,但基本上是如何“剔除”您不想考虑的数组条目。


这是需要记住的一点,因为正常的查询操作不会“过滤”数组元素,那么类似地,
.distinct()
的查询输入也不会这样做,您打算从考虑中删除这些元素。

使用
$aggregate
怎么样?谢谢您的解释。我能自己找出你的第三个例子(1小时后:)。从你提供的三个例子中,第三个看起来最友好。您的订购是否意味着
展开
的使用不如
过滤器
?@MatthewMoisen所有示例都使用
$unwind
,因为需要从阵列中获取“不同”键。区别在于,如果在“you
$unwind
之前”或“after”之后从数组中删除了所需的唯一条目。自然地,在“之前”删除它们会减少整个处理的负载,即“整个管道中的文档扩展总量减少”。因此,使用更少的内存,这是最理想的。
db.test.distinct('foos', {'foos.type': 'bar'})