也许有人知道我们如何修复或解决一些看起来像Azure Cosmos DB中MongoDB的聚合管道当前实现中的错误(是的:我们已经在我们的实例上启用了该功能)。 / p>
简短版本是:在我们看来,<{strong>一个$match
阶段之后的$group
聚合阶段不起作用。它永远不会返回任何结果。
假设您已经在有效的数据库中(使用use <some db>
),可以使用任何Mongo控制台以下列方式重现:
粘贴以下JavaScript(如果您通过Azure门户创建了该集合,则此行是可选的;它假定您的集合名为bug
)
db.createCollection("bug");
将一些文档添加到集合中:
db.bug.insert({ _id: 1, owner: "a", _class: "History" });
db.bug.insert({ _id: 2, owner: "a", _class: "History" });
db.bug.insert({ _id: 3, owner: "a", _class: "DocumentBookmark" });
db.bug.insert({ _id: 4, owner: "a", _class: "Recyclebin" });
db.bug.insert({ _id: 5, owner: "b", _class: "History" });
如您所见,owner: "a"
有一个重复的History
记录,我们要查询该记录。
现在执行以下操作:
db.bug.aggregate([
{ $match: { _class: "History"} }
]);
这会产生正确的结果:
globaldb:PRIMARY> db.bug.aggregate([
... { $match: { _class: "History"} }
... ]);
{
"_t" : "AggregationPipelineResponse",
"ok" : 1,
"waitedMS" : NumberLong(0),
"result" : [
{
"_id" : 1,
"owner" : "a",
"_class" : "History"
},
{
"_id" : 2,
"owner" : "a",
"_class" : "History"
},
{
"_id" : 5,
"owner" : "b",
"_class" : "History"
}
]
}
现在添加一个$group
阶段,其中包含count
,以查找每个所有者的记录数:
db.bug.aggregate([
{ $match: { _class: "History"} },
{ $group: { _id: "$owner", count: { $sum: 1 }}}
]);
这也会返回正确的结果:
globaldb:PRIMARY> db.bug.aggregate([
... { $match: { _class: "History"} },
... { $group: { _id: "$owner", count: { $sum: 1 }}}
... ]);
{
"_t" : "AggregationPipelineResponse",
"ok" : 1,
"waitedMS" : NumberLong(0),
"result" : [
{
"_id" : "a",
"count" : NumberLong(2)
},
{
"_id" : "b",
"count" : NumberLong(1)
}
]
}
现在我们要匹配count
大于1的记录:
db.bug.aggregate([
{ $match: { _class: "History"} },
{ $group: { _id: "$owner", count: { $sum: 1 }}},
{ $match: { count: { $gt: 1 }}}
]);
这将返回空结果集:
globaldb:PRIMARY> db.bug.aggregate([
... { $match: { _class: "History"} },
... { $group: { _id: "$owner", count: { $sum: 1 }}},
... { $match: { count: { $gt: 1 }}}
... ]);
{
"_t" : "AggregationPipelineResponse",
"ok" : 1,
"waitedMS" : NumberLong(0),
"result" : [ ]
}
现在,为了验证这些查询实际上是正确的,我使用mongo:3.4
泊坞窗图像进行了尝试。以下代码将在本地计算机上启动一个新的Mongo数据库实例,以便您可以自己尝试:
$ docker run --name mongobug -d mongo:3.4
ad3010da255b7c15a464fa21ff6519799a5c16cb8af62a0ea564a95780900491
$ docker exec -it mongobug mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
Welcome to the MongoDB shell.
>
然后我们会像上面的Cosmos一样;在Mongo Shell中,运行以下命令:
db.createCollection("bug")
然后插入测试数据:
db.bug.insert({ _id: 1, owner: "a", _class: "History" });
db.bug.insert({ _id: 2, owner: "a", _class: "History" });
db.bug.insert({ _id: 3, owner: "a", _class: "DocumentBookmark" });
db.bug.insert({ _id: 4, owner: "a", _class: "Recyclebin" });
db.bug.insert({ _id: 5, owner: "b", _class: "History" });
现在您可以看到,在运行以下聚合查询时,返回空集的查询实际上会返回非空聚合结果:
db.bug.aggregate([
{ $match: { _class: "History"} },
{ $group: { _id: "$owner", count: { $sum: 1 }}},
{ $match: { count: { $gt: 1 }}}
]);
结果是预期的:
> db.bug.aggregate([
... { $match: { _class: "History"} },
... { $group: { _id: "$owner", count: { $sum: 1 }}},
... { $match: { count: { $gt: 1 }}}
... ]);
{ "_id" : "a", "count" : 2 }
我还尝试先在owner
和_class
的联合组中进行分组,然后$match
;这显然是一个更昂贵的操作,因为Mongo必须分组整个集合,而不仅仅是已经过滤的项目。
但是,不幸的是,这也是一个空洞的结果,而它在当地的Mongo码头图像上工作:
db.bug.aggregate([
{ $group: { _id: { owner: "$owner", _class: "$_class" }, count: { $sum: 1 } } },
{ $match: { "_id._class": "History", count: { $gt: 1 } } }
]);
Cosmos的结果:
globaldb:PRIMARY> db.bug.aggregate([
... { $group: { _id: { owner: "$owner", _class: "$_class" }, count: { $sum: 1 } } },
... { $match: { "_id._class": "History", count: { $gt: 1 } } }
... ]);
{
"_t" : "AggregationPipelineResponse",
"ok" : 1,
"waitedMS" : NumberLong(0),
"result" : [ ]
}
Mongo DB的结果:
> db.bug.aggregate([
... { $group: { _id: { owner: "$owner", _class: "$_class" }, count: { $sum: 1 } } },
... { $match: { "_id._class": "History", count: { $gt: 1 } } }
... ]);
{ "_id" : { "owner" : "a", "_class" : "History" }, "count" : 2 }
怪异。
Cosmos DB是否存在错误,该错误不允许在$match
阶段后运行$group
聚合?
答案 0 :(得分:0)
您的观察结果是正确的。 Cosmos DB尚不支持多个$ match阶段。 $ match必须是第一阶段。在实现支持之前的短期解决方法之一(除了明显的 - 在客户端处理额外的过滤)是使用$ out阶段并利用临时集合,您可以在其上运行另一个聚合管道命令与另一个$比赛。
答案 1 :(得分:0)
自从Azure Cosmos DB for MongoDB API的3.6版发布以来,想要提供对此线程的更新,聚合问题现在返回正确的结果。
初始查询+结果:
db.coll_01.aggregate([
{ $match: { _class: "History"} }
]);
Operation consumed 3.18 RUs
{ "_id" : 1, "owner" : "a", "_class" : "History" }
{ "_id" : 2, "owner" : "a", "_class" : "History" }
{ "_id" : 5, "owner" : "b", "_class" : "History" }
第二次查询+结果:
db.coll_01.aggregate([
{ $match: { _class: "History"} },
{ $group: { _id: "$owner", count: { $sum: 1 }}}
]);
Operation consumed 3.36 RUs
{ "_id" : "a", "count" : 2 }
{ "_id" : "b", "count" : 1 }
最后是聚合查询+结果:
db.coll_01.aggregate([
{ $match: { _class: "History"} },
{ $group: { _id: "$owner", count: { $sum: 1 }}},
{ $match: { count: { $gt: 1 }}}
]);
Operation consumed 3.36 RUs
{ "_id" : "a", "count" : 2 }
有关更多信息,请参见:Azure Cosmos DB's API for MongoDB (3.6 version): supported features and syntax