当前位置: 首页 > 知识库问答 >
问题:

Cosmos DB聚合管道不兼容(Mongo API)?

颛孙庆
2023-03-14

也许有人有一个好主意,我们可以如何修复或解决Azure Cosmos DB中MongoDB聚合管道的当前实现中的一个错误(所以是的:我们已经在实例上打开了该功能)。

简短的版本是:在我们看来,$group阶段之后的$matchaggregation阶段不起作用。它从不返回任何结果。

假设您已经在一个有效的数据库中(使用< code>use

粘贴以下 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" });

如您所见,所有者:“a”有重复的历史记录,我们要查询该记录。

现在执行以下操作:

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"
        }
    ]
}

现在添加一个带有< code>count的< code>$group阶段,以查找每个所有者的记录数:

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.4docker映像进行了尝试。以下代码将在您的本地机器上启动一个新的Mongo DB实例,以便您可以自己尝试:

$ 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 }

我还尝试先按联合组中的< code>owner和< code>_class分组,然后按< code>$match分组;这显然是一个昂贵得多的操作,因为Mongo必须对整个集合进行分组,而不仅仅是对已经过滤的项目进行分组。

但是,不幸的是,这也呈现了一个空结果,而它在本地Mongo html" target="_blank">docker映像上工作:

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是否存在不允许在$group阶段之后运行$匹配聚合的错误?

共有2个答案

凌征
2023-03-14

你的观察是正确的。Cosmos DB还不支持多个$match阶段。$match必须是第一阶段。在实现支持之前,一个短期的解决方法(除了在客户端处理额外的过滤之外)是使用$out stage并利用一个临时集合,在这个集合上,您可以使用另一个$match运行另一个聚合管道命令。

祖翰音
2023-03-14

希望提供此线程的更新,因为版本 3.6 已发布适用于 MongoDB 的 Azure Cosmos DB API,聚合问题现在返回正确的结果。

初始查询结果:

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 }

有关详细信息,请参阅:适用于 MongoDB 的 Azure Cosmos DB API(3.6 版本):支持的功能和语法

 类似资料:
  • 我想知道如何在Elasticsearch中使用聚合时获得具有最高doc_count的存储桶。我正在使用Kibana示例数据kibana_sample_data_flights: 如果有一个存储桶具有最大文档计数,我可以将术语聚合的大小设置为1,但是如果有两个存储桶具有相同的最大文档计数,则这不起作用。 自从我涉足管道聚合以来,我觉得应该有一种简单的方法来实现这一点。最大桶聚合似乎能够处理多个最大桶

  • 我在尝试使用MongooseJs在Mongodb中按嵌套数组排序时遇到了一个小问题。 a)一个产品包含任务,每个任务都有子任务。 b)任务有顺序 这是一个示例产品文档: 结果: } 我正在使用MongoDB聚合管道来订购任务 结果: } 预期结果: 我真的很接近了,所有的排序似乎都在工作。我只需要一些帮助来将子任务放回父母体内。非常感谢任何帮助。 谢谢

  • 我有一个mongo搜索集。每个搜索都有一个criteria对象,该对象可以有任何条件组合。比如: 我正在构建一个mongo聚合管道,我想知道如何只投影密钥,以便我可以计算它们。 到目前为止,我的管道的第一步是: 这将正确返回所有criteria对象,现在我需要以某种方式投影键。有人有什么想法吗? 编辑:所需输出:

  • 我搜索了类似的问题,但没有找到任何问题。请随时为我指出他们的方向。 假设我有这个数据: 如果我想获取每个属性组的最新记录,我可以这样做: 我想让我的数据按属性分组,然后按id排序,这样每个组中只保留最新的记录,这就是我可以做到的。但我需要一种方法来避免在结果中命名我想要的所有字段(在本例中为“name”),因为在我的实际用例中,它们在前面是未知的。 那么,有没有办法做到这一点,但不必使用$last

  • 我试图使用MongoDb列出展开嵌套数组。 一个产品包含任务,每个任务可以有零个、一个或多个子任务。 以下是产品文档示例: 结果: 聚合管道在对任务进行排序方面起到了很大的作用 有时任务没有子任务,例如: 当他们没有孩子的时候,还有什么可以帮助他们完成任务吗? 当前聚合: 期望的结果:

  • 我目前正在我的一个Java脚本中开发mongoDB聚合管道。 输入数据可以简化为不同客户的订单列表。例如: _id、customerId和orderId是字符串,金额是一个Long类型的数字,装运是名为shipping的自定义类的实体。现在,我想汇总这些数据,并显示每个customerId的总花费和所有发货量。对于第一位客户: {CusterId:123,发货:[发货1,发货2,发货4],金额:5