MongoDB C# - 如何对记录上的对象数组进行排序和分页

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

我有一个 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 个英雄,我想返回所有记录,但按属性排序并返回分页。

c# mongodb sorting mongodb-.net-driver
1个回答
1
投票

在 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"
    ]
  }
])

演示@Mongo Playground


在 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();
© www.soinside.com 2019 - 2024. All rights reserved.