【问题标题】:Group by Multiple Fields In Meteor在 Meteor 中按多个字段分组
【发布时间】:2017-09-03 21:41:57
【问题描述】:

我想要实现的是,在给定的日期范围内,我想先按 time 对用户进行分组,然后按 userId 分组。

我试过下面的查询按多个字段分组,

ReactiveAggregate(this, Questionaire,
[
    {
        "$match": {
            "time": {$gte: fromDate, $lte: toDate},
            "userId": {'$regex' : regex}
        }
    },
    {
        $group : {
            "_id": {
                "userId": "$userId",
                "date": { $dateToString: { format: "%Y-%m-%d", date: "$time" } }
            },
            "total": { "$sum": 1 }
           }
    }
], { clientCollection: "Questionaire" }
);

但是当我在服务器端执行它时,它会显示以下错误,

Exception from sub Questionaire id kndfrx9EuZ5EejKmE 
Error: Meteor does not currently support objects other than ObjectID as ids

【问题讨论】:

    标签: javascript mongodb meteor aggregation-framework


    【解决方案1】:

    消息实际上说明了一切,因为您通过 $group 生成的“复合”_id 值实际上在将发布的 clientCollection 输出中不受支持。

    当然,简单的解决方案是不使用来自$group_id 值作为生成输出中的“最终”_id 值。因此,正如 project README 上的示例所示,只需添加一个 $project 即可删除 _id 并将当前的“复合分组键”重命名为不同的属性名称:

    ReactiveAggregate(this, Questionaire,
    [
        {
            "$match": {
                "time": {$gte: fromDate, $lte: toDate},
                "userId": {'$regex' : regex}
            }
        },
        {
            $group : {
                "_id": {
                    "userId": "$userId",
                    "date": { $dateToString: { format: "%Y-%m-%d", date: "$time" } }
                },
                "total": { "$sum": 1 }
               }
        },
        // Add the reshaping to the end of the pipeline
        {
            "$project": {
                "_id": 0,           // remove the _id, this will be automatically filled
                "userDate": "$_id", // the renamed compound key
                "total": 1
            }
        }
    ], { clientCollection: "Questionaire" }
    );
    

    字段顺序会有所不同,因为 MongoDB 会保留现有字段(即本示例中的 "total"),然后将任何新字段添加到文档中。您可以通过在 $group$project 阶段而不是 1 包含语法中使用不同的字段名称来计算这一点。

    如果没有这样的插件,这种重塑是有 been regularly done in the past 的东西,通过再次重命名输出 _id 并提供一个新的 _id 值,该值与流星客户端集合期望出现在此属性中的内容兼容。


    仔细检查how the code is implemented,最好在结果中实际提供_id 值,因为插件实际上不会创建_id 值。

    因此,只需在分组中提取现有文档_id 值之一就足够了。所以我会添加一个$max 来执行此操作,然后替换$project 中的_id

    ReactiveAggregate(this, Questionaire,
    [
        {
            "$match": {
                "time": {$gte: fromDate, $lte: toDate},
                "userId": {'$regex' : regex}
            }
        },
        {
            $group : {
                "_id": {
                    "userId": "$userId",
                    "date": { $dateToString: { format: "%Y-%m-%d", date: "$time" } }
                },
                "maxId": { "$max": "$_id" },
                "total": { "$sum": 1 }
               }
        },
        // Add the reshaping to the end of the pipeline
        {
            "$project": {
                "_id": "$maxId",           // replaced _id
                "userDate": "$_id",       // the renamed compound key
                "total": 1
            }
        }
    ], { clientCollection: "Questionaire" }
    );
    

    replacing the lines 可以在插件中轻松修补此问题

      if (!sub._ids[doc._id]) {
        sub.added(options.clientCollection, doc._id, doc);
      } else {
        sub.changed(options.clientCollection, doc._id, doc);
      }
    

    当管道输出的文档尚不存在_id 值时,使用Random.id()

      if (!sub._ids[doc._id]) {
        sub.added(options.clientCollection, doc._id || Random.id(), doc);
      } else {
        sub.changed(options.clientCollection, doc._id || Random.id(), doc);
      }
    

    但这可能是作者考虑更新软件包的注意事项。

    【讨论】:

    • 哦!所以$Project 是所有必须改变的。谢谢吨!让我试试这个,然后回到结论。
    • @AnkurSoni 重点是基本上删除错误所抱怨的“compound _id”值。根据文档,这应该使用默认值自动填充到创建的客户端集合中。我还链接到来自 Andrew Mao 的可敬回复,出于同样的原因,我们之前在已发布集合的 _id 中使用 Random.id() 填充了返回的内容。
    • @AnkurSoni 我看到您尝试进行编辑,但编辑应该与结果无关。包含复合值的特定属性(结果集合中的 _id 除外)没有任何问题,因为它完全有效。这样做的原因是为了与您提出的问题保持一致。如果您希望自己的输出中有单独的字段,那么这取决于您自己的实现。但这与问题或答案无关。
    • 我同意!但是由于我正在执行您的代码,所以我的 UI 上没有填充任何内容,错误是 Uncaught Error: Expected to find a document already present for removed。是因为_id被压制了吗?
    • @AnkurSoni 这听起来与这里的代码无关。也许您需要重新启动项目。如果我有时间,我可以尝试用一个最小的例子来启动一个流星实例。但是一般的“复合_id”问题是我所知道的(因此是答案),并且通过文档会生成一个新的_id“应该”。您可能还想直接检查目标集合并查看其中的内容。如果您使用像 collection2 之类的东西,其定义的模式与输出形状不匹配,请小心。
    猜你喜欢
    • 2018-11-28
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    相关资源
    最近更新 更多