【问题标题】:Cosmos DB Aggregation Pipeline incompatible (Mongo API)?Cosmos DB 聚合管道不兼容(Mongo API)?
【发布时间】:2018-01-22 12:20:59
【问题描述】:

也许有人有一个很好的想法,我们可以如何修复或解决某些问题,这看起来像是 Azure Cosmos DB 中 MongoDB 聚合管道的当前实现中的一个错误(所以是的:我们已经在我们的实例上启用了该功能)。

简短的版本是:在我们看来,$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"
        }
    ]
}

现在添加一个带有count$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 DB 上也是如此

现在,为了验证这些查询实际上是否正确,我使用mongo:3.4 docker 映像进行了尝试。以下代码将在您的本地机器上启动一个新的 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 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 }

很奇怪。

tl;博士

Cosmos DB 是否存在不允许在 $group 阶段之后运行 $match 聚合的错误?

【问题讨论】:

  • 只需使用 Atlas 在 Azure 中运行 MongoDB! ;-)
  • 嗯,是的,好吧,甚至可能是一种选择,但它显然不能直接从市场上获得,而且我不希望有额外的地方向我们收费。我们需要基于 API 的供应和扩展。我仍然希望 Cosmos 能够解决这个问题。
  • 啊,对了,我听说使用 MongoDB API 时,并非一切都如您所愿。
  • 不幸的是,没有。但它工作得很好,你认为它确实有效,直到它没有......

标签: mongodb azure azure-cosmosdb


【解决方案1】:

自从 3.6 版 Azure Cosmos DB for MongoDB 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 }

更多信息请查看:Azure Cosmos DB's API for MongoDB (3.6 version): supported features and syntax

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 虽然我不太想待在这里...关于此的任何 ETA 吗?我们现在会解决它,但我们并不高兴。这些东西有记录吗?阅读文档(我们做过),您会得到印象,列出的阶段完全支持聚合管道(其中 $match 是其中之一)。我将在文档中添加评论并在此处链接。
    • 请做。根据 StackOverflow 指南,我们无法在此处提供 ETA
    猜你喜欢
    • 2019-08-01
    • 1970-01-01
    • 2023-02-21
    • 2021-06-15
    • 2020-05-11
    • 2021-11-14
    • 2022-11-23
    • 1970-01-01
    • 2019-06-05
    相关资源
    最近更新 更多