我有一个 MongoDB,里面有一个集合:people。
[
{
_id: 0,
name: "lucas",
properties: [
{
Name: "powers",
Values: [
"fireball",
"icebeam",
"thunderbolt"
]
},
{
Name: "weakness",
Values: [
"poison",
"rain"
]
}
]
},
{
_id: 1,
name: "cage",
properties: [
{
Name: "powers",
Values: [
"flight",
"strength",
"fireball"
]
},
{
Name: "weakness",
Values: [
"lightning",
"ice"
]
}
]
},
{
_id: 2,
name: "joe",
properties: [
{
Name: "powers",
Values: [
"immortality",
"strength",
"flight"
]
}
]
},
{
_id: 3,
name: "bob",
properties: [
{
Name: "weakness",
Values: [
"cold",
"flu",
"no food"
]
}
]
}
]
我故意省略了“joe”的“弱点”属性和“bob”的“权力”属性,因为并非所有人都有弱点或权力。我不确定如何根据属性“权力”的值对所有记录进行排序。假设我有 50 个英雄,我想返回所有记录,但按属性排序并返回分页。
在 MongoDB 查询中,在执行排序之前需要提取 powers 数组及其大小 (
powersLength
)。
之后,删除这两个字段,以便它们不会显示在结果中。
db.collection.aggregate([
{
$set: {
properties: {
$map: {
input: "$properties",
in: {
$mergeObjects: [
"$$this",
{
Values: {
$sortArray: {
input: "$$this.Values",
sortBy: 1
}
}
}
]
}
}
}
}
},
{
$set: {
powers: {
$getField: {
field: "Values",
input: {
$first: {
$filter: {
input: "$properties",
cond: {
$eq: [
"$$this.Name",
"powers"
]
}
}
}
}
}
}
}
},
{
$set: {
powersLength: {
$size: {
$ifNull: [
"$powers",
[]
]
}
}
}
},
{
$sort: {
powersLength: -1,
powers: 1
}
},
{
$unset: [
"powers",
"powersLength"
]
}
])
在 MongoDB .NET Driver 语法中,我认为这很复杂,并且可能无法使用完整的 Fluent API 语法来实现。
但是您可以通过 MongoDB Compass(导出到语言功能)将查询翻译为
BsonDocument
。
var pipeline = new BsonDocument[]
{
new BsonDocument("$set",
new BsonDocument("powers",
new BsonDocument("$getField",
new BsonDocument
{
{ "field", "Values" },
{ "input",
new BsonDocument("$first",
new BsonDocument("$filter",
new BsonDocument
{
{ "input", "$properties" },
{ "cond",
new BsonDocument("$eq",
new BsonArray
{
"$$this.Name",
"powers"
}) }
})) }
}))),
new BsonDocument("$set",
new BsonDocument("powersLength",
new BsonDocument("$size",
new BsonDocument("$ifNull",
new BsonArray
{
"$powers",
new BsonArray()
})))),
new BsonDocument("$sort",
new BsonDocument
{
{ "powersLength", -1 },
{ "powers", 1 }
}),
new BsonDocument("$unset",
new BsonArray
{
"powers",
"powersLength"
})
};
var result = await _col.Aggregate<People>(pipeline)
.ToListAsync();
或者部分使用 Fluent API:
var setStageFirst = new BsonDocument("$set",
new BsonDocument("powers",
new BsonDocument("$getField",
new BsonDocument
{
{ "field", "Values" },
{ "input",
new BsonDocument("$first",
new BsonDocument("$filter",
new BsonDocument
{
{ "input", "$properties" },
{ "cond",
new BsonDocument("$eq",
new BsonArray
{
"$$this.Name",
"powers"
})
}
}))
}
})));
var setStageSecond = new BsonDocument("$set",
new BsonDocument("powers",
new BsonDocument("$getField",
new BsonDocument
{
{ "field", "Values" },
{ "input",
new BsonDocument("$first",
new BsonDocument("$filter",
new BsonDocument
{
{ "input", "$properties" },
{ "cond",
new BsonDocument("$eq",
new BsonArray
{
"$$this.Name",
"powers"
})
}
}))
}
})));
var setStageThird = new BsonDocument("$set",
new BsonDocument("powersLength",
new BsonDocument("$size",
new BsonDocument("$ifNull",
new BsonArray
{
"$powers",
new BsonArray()
}))));
var sortStage = new BsonDocument
{
{ "powersLength", -1 },
{ "powers", 1 }
};
var unsetStage = new BsonDocument("$unset",
new BsonArray
{
"powers",
"powersLength"
});
var result = await _col.Aggregate()
.AppendStage<BsonDocument>(setStageFirst)
.AppendStage<BsonDocument>(setStageSecond)
.AppendStage<BsonDocument>(setStageThird)
.Sort(sortStage)
.AppendStage<People>(unsetStage)
.ToListAsync();