Вам нужен оператор $ facet , чтобы запустить более одного конвейера агрегации одновременно, а затем обработать результат, используя результат, возвращаемый несколькими конвейерами.
db.col.aggregate([
{
$match: q
},
{
$facet: {
count: [{ $count: "total" }],
docs: [ { $match: q } ] // this is supposed to pass all input documents to the output but we can't specify empty array here thus we can repeat q
}
},
{
$unwind: "$count"
},
{
$project: {
docs: {
$slice: [ "$docs", { $multiply: [ -1, { $ceil: { $divide: [ "$count.total", 2 ] } } ] } ]
}
}
},
{
$unwind: "$docs"
},
{
$replaceRoot: {
newRoot: "$docs"
}
}
])
Каждый этап, определенный в $facet
вернет массив, однако мы знаем, что count должен содержать только один элемент, поэтому мы можем использовать $ unwind .Второе поле (docs
) будет содержать все элементы, которые были возвращены после запроса q
.Для получения последних k
элементов вы можете использовать $ slice , передавая отрицательное значение в качестве второго параметра (принимает последние k
элементов).Затем вам нужно преобразовать секционированный массив обратно в исходную форму, поэтому вам нужно $unwind
и $ replaceRoot .
Поскольку агрегация немного сложна, возможно, лучшим вариантом в C # является использование BsonDocument
класс, попробуйте:
FilterDefinition<BsonDocument> q = // your query
AggregateFacet<BsonDocument> countFacet =
AggregateFacet.Create<BsonDocument, BsonDocument>("count",
PipelineDefinition<BsonDocument, BsonDocument>.Create(new IPipelineStageDefinition[] {
new BsonDocumentPipelineStageDefinition<BsonDocument, BsonDocument>(BsonDocument.Parse("{ $count: \"total\" }"))
}));
AggregateFacet<BsonDocument> matchFacet =
AggregateFacet.Create<BsonDocument, BsonDocument>("docs",
PipelineDefinition<BsonDocument, BsonDocument>.Create(new IPipelineStageDefinition[] {
PipelineStageDefinitionBuilder.Match(q)
}));
var projection = new BsonDocumentProjectionDefinition<BsonDocument>(
BsonDocument.Parse("{ docs: { $slice: [ \"$docs\", { $multiply: [ -1, { $ceil: { $divide: [ \"$count.total\", 2 ] } } ] } ] } }"));
var replaceRoot = new BsonValueAggregateExpressionDefinition<BsonDocument, BsonDocument>("$docs");
var result = Col.Aggregate()
.Match(q)
.Facet<BsonDocument>(new[] { countFacet, matchFacet })
.Unwind("count")
.Project(projection)
.Unwind("docs")
.ReplaceRoot(replaceRoot)
.ToList<BsonDocument>();