这里似乎对 MongoDB distinct 命令的工作方式或任何查询如何与数组一起工作存在误解。
我将考虑您实际上拥有的文档看起来像这样:
{
"_id" : ObjectId("5398f8bf0b5d1b43d3e26816"),
"bar" : [
{
"baz" : [
"one",
"two"
]
},
{
"baz" : [
"three"
]
},
{
"baz" : [
"one",
"four"
]
}
]
}
所以你运行的查询,这两种形式是等价的:
db.runCommand({
"distinct": "foo",
"query": { "bar.baz": "one" },
"key": "bar.baz"
})
db.foo.distinct("bar.baz", { "bar.baz": "one" })
基本上返回这个:
[ "four", "one", "three", "two" ]
为什么?好吧,因为你要求它。让我们考虑一种描述您实际调用的内容的声明方式。
你的“查询”本质上是说'找到所有“bar.baz”等于“one”的“文档”'然后你问'然后把所有的都还给我“bar.baz”的“不同”值
因此,您的语句的“查询”部分正是这样做的,并且匹配了“文档”,而不是与您指定的值匹配的数组成员。在上面的示例中,您随后要求“bar.baz”的“不同”值,这正是您得到的,只有“一个”的值从“bar.baz”的所有值返回一次”。
所以“查询”语句不会“过滤”数组内容,它们只是“匹配”条件存在的地方。上述文档符合条件,“bar.baz”的值为“one”,甚至两次。所以选择不同的“foo”或者基本上是文档真的是:
db.foo.find({ "bar.baz": "one" })
匹配所有满足条件的文档。这就是嵌入的工作方式,但也许您想要过滤结果之类的东西。因此,如果只返回那些“baz”值为“one”的“bar”项目,您会这样做:
db.collection.aggregate([
// Matches documents
{ "$match": { "bar.baz": "one" } },
// Unwind to de-normalize arrays as documents
{ "$unwind": "$bar" },
// Match to "filter" documents without "bar.baz" matching "one"
{ "$match": { "bar.baz": "one" } },
// Maybe group back to document with the array
{ "$group": {
"_id": "$_id",
"bar": { "$push": "$bar" }
}}
])
这个.aggregate() 语句的结果是没有“bar”成员且“baz”下不包含“one”的文档:
{
"_id" : ObjectId("5398f8bf0b5d1b43d3e26816"),
"bar" : [
{
"baz" : [
"one",
"two"
]
},
{
"baz" : [
"one",
"four"
]
}
]
}
但是假设您实际上只希望元素“bar.baz”等于“one”以及这些出现在整个集合中的总数,那么您会想要这样做:
db.collection.aggregate([
// Matches documents
{ "$match": { "bar.baz": "one" } },
// Unwind to de-normalize arrays as documents
{ "$unwind": "$bar" },
// And the inner array as well
{ "$unwind": "$bar.baz" },
// Then just match and filter out everything but the matching items
{ "$match": { "bar.baz": "one" } },
// Group to get the count
{ "$group": {
"_id": "$bar.baz",
"count": { "$sum": 1 }
}}
])
您可以从我们的单一文档收集示例中获得:
{ "_id": "one", "count": 2 }
因为该匹配值出现了两次。
至于您的问题开头的 SQL,这确实不适用于此类数据。更实际的例子是这样的数据:
{ "A": "A", "B": "BASDFJJ" }
{ "A": "A", "B": "ASDFTT" }
{ "A": "B", "B": "CASDF" }
{ "A": "B", "B": "DKITB" }
所以“A”的“不同”值,其中“B”类似于“ASDF”,再次使用聚合并注意您在任何一方都没有通配符:
db.foo.aggregate([
{ "$match": { "B": "ASDF" } },
{ "$group": { "_id": "$A" } }
])
本质上产生:
{ "_id": "A" }
或者在 "%ASDF%" 两边使用通配符,这是要匹配的 $regex 查询:
db.foo.aggregate([
{ "$match": { "B": { "$regex": "ASDF" } } },
{ "$group": { "_id": "$A" } }
])
所以只有两个结果:
{ "_id": "A" }
{ "_id": "B" }
如果您“计算”不同的匹配项,那么根据匹配的文档,您会看到 2 和 1 分别作为计数。
进一步查看文档中包含的SQL Mapping Chart 和SQL to Aggregation Mapping Chart。它应该可以帮助您了解常见操作的实际转化方式。