如何从多个字段中按最小值排序?

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

我有 mongo 文档列表

[
  {
    "created_at": "2024-03-15T18:11:18.687",
    "updated_at": "2024-03-15T18:11:28.945",
    "fields": {
      "contract_first": [],
      "contract_second": [
        {
          "position": "Bob"
        }
      ],
      "uuid": "bf031b46-ec33-4c61-ad33-a3ad2cbeb9cb"
    },
    "id": "65f46520928f6fd496ffbe6d"
  },
  {
    "created_at": "2024-03-15T18:11:18.687",
    "updated_at": "2024-03-15T18:15:26.838",
    "fields": {
      "contract_first": [
        {
          "position": "Anna"
        }
      ],
      "contract_second": [],
      "uuid": "bf052b46-ec33-4c61-ad33-a3ad2cbeb9cb"
    },
    "id": "65f4660e928f6fd496ffbeb0"
  },
  {
    "created_at": "2024-03-15T18:11:18.687",
    "updated_at": "2024-03-15T18:15:26.838",
    "fields": {
      "contract_first": [
        {
          "position": "Bob"
        }
      ],
      "contract_second": [],
      "uuid": "bf092b46-ec33-4c61-ad33-a3ad2cbeb9cb"
    },
    "id": "65f8660e928f6fd496ffbeb0"
  }
]

其中有 2 个主要数组字段

contract_first
contract_second
,我想知道如何按 2 个数组字段对我的文档进行排序?

我正在尝试使用

{
  '$sort': {
    'fields.contract_first.position': 1,
    'fields.contract_second.position': 1
  }
}

但是我有一个错误

cannot sort with keys that are parallel arrays

例如输出应该是这样的: 安娜 鲍勃 鲍勃 即使他们在不同的领域

arrays mongodb mongodb-query
3个回答
2
投票

从 mongoDB 5.2 版本开始,一种选择是:

db.collection.aggregate([
  {$set: {sort_key: {$sortArray: {
          input: {
            $concatArrays: [
              "$fields.contract_first.position",
              "$fields.contract_second.position"
            ]
          },
          sortBy: 1
  }}}},
  {$sort: {sort_key: 1}},
  {$unset: "sort_key"}
])

查看它在 mongoDB Playground 上的工作原理


1
投票

即使在

{ contract_first: [{ position: "Ellen" }], contract_second: [] }
vs
{ contract_first: [], contract_second: [{ position: "Dave" }] }

的情况下,我也希望“Dave”位于“Ellen”之前

如果只有第一个或第二个合约有一个条目,但不是两者都有,那么你可以这样做:
根据每个值的第一个非空值分配一个 sort_key,然后根据该值进行排序。

db.collection.aggregate([
  {
    $set: {
      sort_key: {
        $ifNull: [
          { $first: "$fields.contract_first.position" },
          { $first: "$fields.contract_second.position" }
        ]
      }
    }
  },
  { $sort: { sort_key: 1 } }
])

但是,如果第一个和第二个合约都可以存在,您需要将第二个合约重新添加为 sort_key。

所以在这里,我创建了其中两个:

sort_key1
是第一个非空合约,位置在
first_contract
second_contract
之间,而
sort_key2
只是
second_contract
。因此,当
sort_key2
相同时,将使用
sort_key1

db.collection.aggregate([
  {
    $set: {
      sort_key1: {
        $ifNull: [
          { $first: "$fields.contract_first.position" },
          { $first: "$fields.contract_second.position" }
        ]
      },
      sort_key2: { $first: "$fields.contract_second.position" }
    }
  },
  {
    $sort: {
      sort_key1: 1,
      sort_key2: 1
    }
  },
  {
    // comment this out to see the sort_keys
    $unset: ["sort_key1", "sort_key2"]
  }
])

Mongo Playground 具有更好的数据示例。


0
投票

对于涉及自定义排序逻辑的用例,常见的解决方案模式之一是创建自定义排序键并对其进行排序。这提供了灵活性,因为如果情况发生变化,您可以简单地更新排序键的逻辑。

对于您的情况,我创建了一个具有以下逻辑的

sortKey

  1. 选择
    contract_first.position
    ,如果为空,
    $ifNull
    回退到MaxKey(MongoDB中排序的最大类型,请参阅this doc,或者您可以使用任何您确定会大于的值该字段中可能的值)
  2. 选择
    contract_second.position
    ,如果为空,
    $ifNull
    回退到MaxKey
  3. 从 1 和 2 的结果中选择
    $min

创建排序键后,只需对结果进行排序即可。使用后请随意删除排序键。如果您不想经常计算密钥,您可以具体化/保留密钥。

db.collection.aggregate([
  {
    "$set": {
      "sortKey": {
        "$min": [
          {
            "$ifNull": [
              {
                "$first": "$fields.contract_first.position"
              },
              {
                "$maxKey": 1
              }
            ]
          },
          {
            "$ifNull": [
              {
                "$first": "$fields.contract_second.position"
              },
              {
                "$maxKey": 1
              }
            ]
          }
        ]
      }
    }
  },
  {
    "$sort": {
      "sortKey": 1
    }
  },
  {
    "$unset": "sortKey"
  }
])

蒙戈游乐场

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