Mongodb排序内部数组

Ric*_*ann 24 mongodb aggregation-framework

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

{
    "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")
              }
            ]
        }
     }
 }
Run Code Online (Sandbox Code Playgroud)

所以我想保持项目作为服务返回,但我的更新数组已排序.到目前为止,我有shell:

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

有人认为他们可以提供帮助吗?

Joh*_*yHK 47

您可以通过$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'}})
Run Code Online (Sandbox Code Playgroud)

  • 如果应用程序有一个像“名称”这样的字段,并且我也想将该名称保留在结果集中怎么办? (2认同)

Xav*_*hot 13

从 开始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") }
//   ]}}
// }
Run Code Online (Sandbox Code Playgroud)

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

$function 需要3个参数:

  • body,这是要应用的函数,其参数是要修改的数组。
  • args,其中包含该body函数作为参数的记录字段。在我们的情况下"$service.apps.updates"
  • lang,这body是编写函数的语言。仅js当前可用。

  • 对于 Atlas 用户,“$function”在免费套餐中不可用(截至 2021 年 5 月) (2认同)

Xav*_*hot 12

从 开始Mongo 5.2,这就是新$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") }
//   ]}}
// }
Run Code Online (Sandbox Code Playgroud)

这:

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