【问题标题】:Mongodb sort inner arrayMongodb排序内部数组
【发布时间】:2013-03-01 13:17:36
【问题描述】:

我一直在寻找一段时间,但似乎无法对内部数组进行排序并将其保留在我当前正在使用的文档中。

{
    "service": {
        "apps": {
            "updates": [
              {
                "n" : 1
                "date": ISODate("2012-03-10T16:15:00Z")
              },
              {
                "n" : 2
                "date": ISODate("2012-01-10T16:15:00Z")
              },
              {
                "n" : 5
                "date": ISODate("2012-07-10T16:15:00Z")
              }
            ]
        }
     }
 }

所以我想保留要作为服务返回的项目,但要对我的更新数组进行排序。到目前为止,我拥有的外壳:

db.servers.aggregate(
        {$unwind:'$service'},
        {$project:{'service.apps':1}},
        {$unwind:'$service.apps'}, 
        {$project: {'service.apps.updates':1}}, 
        {$sort:{'service.apps.updates.date':1}});

有人认为他们可以在这方面提供帮助吗?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    您可以通过$unwindupdates 数组来执行此操作,按date 对生成的文档进行排序,然后$group使用排序顺序将它们重新放在_id 上。

    db.servers.aggregate(
        {$unwind: '$service.apps.updates'}, 
        {$sort: {'service.apps.updates.date': 1}}, 
        {$group: {_id: '$_id', 'updates': {$push: '$service.apps.updates'}}}, 
        {$project: {'service.apps.updates': '$updates'}})
    

    【讨论】:

    • 太棒了!我对聚合还很陌生,感觉它可以做这样的事情。
    • 如果应用程序有一个像“名称”这样的字段,我想在结果集中保留名称怎么办?
    • @user1251624 您可以将该字段包含在$group 中(在_id 中或作为单独的字段)和$project。如果您需要更多帮助,最好将其作为一个单独的问题提出,因为它可能很重要。
    • @JohnnyHK grouping 在sort 之后的顺序总是保证吗?
    • @RaR 对于$push 是的,AFAIK。对于$addToSet 不,很遗憾。
    【解决方案2】:

    Mongo 4.4 开始,$function 聚合运算符允许应用自定义 javascript 函数来实现 MongoDB 查询语言不支持的行为。

    例如,为了按其中一个字段对对象数组进行排序:

    // {
    //   "service" : { "apps" : { "updates" : [
    //     { "n" : 1, "date" : ISODate("2012-03-10T16:15:00Z") },
    //     { "n" : 2, "date" : ISODate("2012-01-10T16:15:00Z") },
    //     { "n" : 5, "date" : ISODate("2012-07-10T16:15:00Z") }
    //   ]}}
    // }
    db.collection.aggregate(
      { $set: {
        { "service.apps.updates":
          { $function: {
              body: function(updates) {
                updates.sort((a, b) => a.date - b.date);
                return updates;
              },
              args: ["$service.apps.updates"],
              lang: "js"
          }}
        }
      }
    )
    // {
    //   "service" : { "apps" : { "updates" : [
    //     { "n" : 2, "date" : ISODate("2012-01-10T16:15:00Z") },
    //     { "n" : 1, "date" : ISODate("2012-03-10T16:15:00Z") },
    //     { "n" : 5, "date" : ISODate("2012-07-10T16:15:00Z") }
    //   ]}}
    // }
    

    这会就地修改数组,而无需应用昂贵的$unwind$sort$group 阶段的组合。

    $function 接受 3 个参数:

    • body,即要应用的函数,其参数是要修改的数组。
    • args,其中包含 body 函数作为参数的记录中的字段。在我们的例子中是"$service.apps.updates"
    • lang,这是编写 body 函数的语言。目前只有 js 可用。

    【讨论】:

    • 对于 Atlas 用户,$function 在免费套餐中不可用(截至 2021 年 5 月)
    【解决方案3】:

    Mongo 5.2release schedule 开始,这是新的 $sortArray 聚合运算符的确切用例:

    // {
    //   service: { apps: { updates: [
    //     { n: 1, date: ISODate("2012-03-10") },
    //     { n: 2, date: ISODate("2012-01-10") },
    //     { n: 5, date: ISODate("2012-07-10") }
    //   ]}}
    // }
    db.collection.aggregate([
      { $set: {
        "service.apps.updates": {
          $sortArray: {
            input: "$service.apps.updates",
            sortBy: { date: 1 }
          }
        }
      }}
    ])
    // {
    //   service: { apps: { updates: [
    //     { n: 2, date: ISODate("2012-01-10") },
    //     { n: 1, date: ISODate("2012-03-10") },
    //     { n: 5, date: ISODate("2012-07-10") }
    //   ]}}
    // }
    

    这个:

    • 排序 ($sortArray) service.apps.updates 数组 (input: "$service.apps.updates")
    • 通过对dates (sortBy: { date: 1 }) 应用排序
    • 无需组合使用昂贵的 $unwind$sort$group 阶段

    【讨论】:

      猜你喜欢
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 1970-01-01
      • 2022-12-16
      • 2019-05-07
      相关资源
      最近更新 更多