根据字段排序并在结果顶部添加特定记录

问题描述 投票:0回答:2

我有以下一组用户记录,我需要以这样的方式获得结果:已登录的用户(

ObjectId("653222c20489664953bbaf1a")
status: Active
)应该首先出现,然后是具有
status: Pending
的用户,最后是其余的用户
status: Active
用户。

如何使用 MongoDB 查询实现此目的?

[
  {
    "_id" : ObjectId("654b7348e704b8abba8af17e"),
    "name": "",
    "email" : "",
    "status" : "Active"
  },
  {
    "_id" : ObjectId("654b6c662f38d9e087086193"),
    "name": "",
    "email" : "",
    "status" : "Pending"
  },
  {
    "_id" : ObjectId("654b7fbae8392eddee2d1a31"),
    "name": "",
    "email" : "",
    "status" : "Pending"
  },
  {
    "_id" : ObjectId("653222c20489664953bbaf1a"),
    "name": "",
    "email" : "",
    "status" : "Active"
  },
  {
    "_id" : ObjectId("653269653bc13f1b96c6c37d"),
    "name": "",
    "email" : "",
    "status" : "Active"
  }
]
mongodb sorting mongodb-query
2个回答
1
投票

解决方案1:

  1. $facet
    - 允许在单个查询中运行多个管道。每个管道包含返回不同数据集的过滤条件。

  2. $project
    - 装饰输出文档。将前一阶段的数据集合并到一个数组中。

  3. $unwind
    - 解构
    users
    数组。

  4. $replaceWith
    - 将输入文档替换为
    users
    文档。

db.collection.aggregate([
  {
    $facet: {
      loginUsers: [
        {
          $match: {
            _id: ObjectId("653222c20489664953bbaf1a"),
            status: "Active"
          }
        }
      ],
      pendingUsers: [
        {
          $match: {
            status: "Pending"
          }
        }
      ],
      activeUsers: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $eq: [
                    "$status",
                    "Active"
                  ]
                },
                {
                  $ne: [
                    "$_id",
                    ObjectId("653222c20489664953bbaf1a")
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  },
  {
    $project: {
      _id: 0,
      users: {
        $concatArrays: [
          "$loginUsers",
          "$pendingUsers",
          "$activeUsers"
        ]
      }
    }
  },
  {
    $unwind: "$users"
  },
  {
    $replaceWith: "$users"
  }
])

演示解决方案1 @ Mongo Playground


解决方案2:

  1. $set
    - 添加
    rank
    字段以通过
    $switch
    根据条件分配值。

  2. $match
    - 如果文档的状态不是“待处理”和“活动”,请使用
    rank: -1
    删除文档。

  3. $sort
    - 按
    rank
    字段升序排序。

  4. $unset
    - 删除
    rank
    字段。

db.collection.aggregate([
  {
    $set: {
      rank: {
        $switch: {
          branches: [
            {
              case: {
                $and: [
                  {
                    $eq: [
                      "$_id",
                      ObjectId("653222c20489664953bbaf1a")
                    ]
                  },
                  {
                    $eq: [
                      "$status",
                      "Active"
                    ]
                  }
                ]
              },
              then: 0
            },
            {
              case: {
                $eq: [
                  "$status",
                  "Pending"
                ]
              },
              then: 1
            },
            {
              case: {
                $and: [
                  {
                    $ne: [
                      "$_id",
                      ObjectId("653222c20489664953bbaf1a")
                    ]
                  },
                  {
                    $eq: [
                      "$status",
                      "Active"
                    ]
                  }
                ]
              },
              then: 2
            }
          ],
          default: -1
        }
      }
    }
  },
  {
    $match: {
      rank: {
        $ne: -1
      }
    }
  },
  {
    $sort: {
      rank: 1
    }
  },
  {
    $unset: "rank"
  }
])

演示解决方案 2 @ Mongo Playground


0
投票

在您的记录中添加“排序键”字段,一个用于完全匹配,一个用于帐户状态。从0开始< 1, set those field values accordingly. These fields are only in the pipeline/results, they are not added to your actual records.

db.collection.aggregate(
  [
    {
      $addFields: {
        id_you_are_looking_for: {
          $cond: {
            if: { $eq: ["$_id", ObjectId("653222c20489664953bbaf1a")] },
            then: 0,  // exact match gets lowest value
            else: 1,
          },
        },
        acc_status_sort: {
          $cond: {
            if: { $eq: ["$status", "Pending"] },
            then: 0,  // status pending gets lowest value
            else: 1,
          },
        },
      },
    },
    {
      $sort: {
        id_you_are_looking_for: 1,  // first, ascending order sort on exact match
        acc_status_sort: 1,  // then, ascending order sort on status
      },
    },
    // remove the extra fields added
    // comment out this part to see the sorting fields in results
    {
      $project: {
        id_you_are_looking_for: 0,
        acc_status_sort: 0,
      },
    },
  ]
)

Mongo Playground,为了清晰起见,显示了排序键字段。

作为替代方案,您还可以将非精确匹配添加为第一个

else
$cond
的嵌套条件,以使用值
1
2
作为帐户状态,然后仅对一个字段进行排序。

db.collection.aggregate(
  [
    {
      $addFields: {
        acc_status_sort: {
          $cond: {
            if: { $eq: ["$_id", ObjectId("653222c20489664953bbaf1a")] },
            then: 0, // exact match gets lowest value
            else: {
              $cond: {
                if: { $eq: ["$status", "Pending"] },
                then: 1,  // status pending gets the next value
                else: 2,  // all others give the highest value
              },
            },
          },
        },
      },
    },
    { $sort: { acc_status_sort: 1 } },
    { $unset: "acc_status_sort" },  // remove the extra fields added
  ]
)

用于嵌套的 Mongo Playground

$cond

© www.soinside.com 2019 - 2024. All rights reserved.