我有以下一组用户记录,我需要以这样的方式获得结果:已登录的用户(
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"
}
]
解决方案1:
$facet
- 允许在单个查询中运行多个管道。每个管道包含返回不同数据集的过滤条件。
$project
- 装饰输出文档。将前一阶段的数据集合并到一个数组中。
$unwind
- 解构 users
数组。
$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"
}
])
解决方案2:
$set
- 添加 rank
字段以通过 $switch
根据条件分配值。
$match
- 如果文档的状态不是“待处理”和“活动”,请使用 rank: -1
删除文档。
$sort
- 按 rank
字段升序排序。
$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"
}
])
在您的记录中添加“排序键”字段,一个用于完全匹配,一个用于帐户状态。从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
]
)
$cond
。