Как отсортировать по «связанным» полям? - PullRequest
2 голосов
/ 11 октября 2019

Я не уверен, как это сформулировать, но я хотел бы отсортировать следующие данные таким образом, чтобы дочерние сообщения были непосредственно ниже их родителей.

{ "_id" : "oI", "msg" : "Hello", "ts" : ISODate("2019-09-20T01:01:43.749Z") },
{ "_id" : "z", "msg" : "can you hear me?", "ts" : ISODate("2019-09-20T01:01:46.569Z"), "tcount" : 3 },
{ "_id" : "wG", "msg" : "Undsen bichver 2", "ts" : ISODate("2019-09-20T02:00:58.254Z") },
{ "_id" : "BF", "msg" : "Undsen bichver 3", "ts" : ISODate("2019-09-20T02:01:06.784Z") },
{ "_id" : "Jq", "msg" : "Undsen bichver 4", "ts" : ISODate("2019-09-20T02:01:11.785Z") },
{ "_id" : "oP", "parentId" : "z", "msg" : "Test 1", "ts" : ISODate("2019-09-20T01:02:06.860Z") },
{ "_id" : "Mq", "parentId" : "z", "msg" : "Test 2", "ts" : ISODate("2019-09-20T01:05:37.173Z") },
{ "_id" : "Lq", "parentId" : "z", "msg" : "Test 3", "ts" : ISODate("2019-09-20T02:01:24.370Z") }

Сортировка, которую я использовал для отображения приведенного выше результата, выглядит следующим образом:

.sort({ "parentId": 1, "ts": 1 })

Я хочу получить следующий результат:

{ "_id" : "oI", "msg" : "Hello", "ts" : ISODate("2019-09-20T01:01:43.749Z") },
{ "_id" : "z", "msg" : "can you hear me?", "ts" : ISODate("2019-09-20T01:01:46.569Z"), "tcount" : 3 },
{ "_id" : "oP", "parentId" : "z", "msg" : "Test 1", "ts" : ISODate("2019-09-20T01:02:06.860Z") },
{ "_id" : "Mq", "parentId" : "z", "msg" : "Test 2", "ts" : ISODate("2019-09-20T01:05:37.173Z") },
{ "_id" : "Lq", "parentId" : "z", "msg" : "Test 3", "ts" : ISODate("2019-09-20T02:01:24.370Z") },
{ "_id" : "wG", "msg" : "Undsen bichver 2", "ts" : ISODate("2019-09-20T02:00:58.254Z") },
{ "_id" : "BF", "msg" : "Undsen bichver 3", "ts" : ISODate("2019-09-20T02:01:06.784Z") },
{ "_id" : "Jq", "msg" : "Undsen bichver 4", "ts" : ISODate("2019-09-20T02:01:11.785Z") }

Обратите внимание на записи с"parentId" : "z" находятся непосредственно под его родителем ("_id" : "z")

Возможно ли сделать что-то подобное?

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Используйте $ addFields и $ ifNull , чтобы создать новое поле, которое затем можно отсортировать по:

db.collection.aggregate([
    {
        $addFields: {
            sortBy: { $ifNull: [ "$parentId", "$_id" ] }
        }
    },
    {
        $sort: {
            sortBy: -1, parentId: 1
        }
    }
])

Mongo Playground

0 голосов
/ 11 октября 2019

Мне удалось добиться желаемой сортировки с помощью следующего:

db.collection.aggregate([
  {
    $lookup: {
      from: "collection",
      localField: "parentId",
      foreignField: "_id",
      as: "parent"
    }
  },
  {
    $addFields: {
      fake_ts: {
        $cond: {
          if: { $eq: [ { $size: "$parent" }, 1 ] },
          then: "$parent.ts",
          else: "$ts"
        }
      }
    }
  },
  {
    $sort: { 
      fake_ts: 1,
      ts: 1
    }
  },
  {
    $project: {
      fake_ts: 0,
      parent: 0
    }
  }
])

Где я сначала присоединяюсь к себе, чтобы получить родительский элемент в каждом дочернем документе, затем я создаюфиктивное поле (идея из @mickl) и использование родительского ts для дочерних документов. Тогда я просто $sort & $project из временных полей.

Сортировка выполняется сначала fake_ts, затем ts, так что мыдочерние документы будут всегда находиться под родительским, но они будут отсортированы между собой по ts.

В результате вы получите:

[
  {
    "_id": "oI",
    "msg": "Hello",
    "ts": ISODate("2019-09-20T01:01:43.749Z")
  },
  {
    "_id": "z",
    "msg": "can you hear me?",
    "tcount": 3,
    "ts": ISODate("2019-09-20T01:01:46.569Z")
  },
  {
    "_id": "oP",
    "msg": "Test 1",
    "parentId": "z",
    "ts": ISODate("2019-09-20T01:02:06.86Z")
  },
  {
    "_id": "Mq",
    "msg": "Test 2",
    "parentId": "z",
    "ts": ISODate("2019-09-20T01:05:37.173Z")
  },
  {
    "_id": "Lq",
    "msg": "Test 3",
    "parentId": "z",
    "ts": ISODate("2019-09-20T02:01:24.37Z")
  },
  {
    "_id": "wG",
    "msg": "Undsen bichver 2",
    "ts": ISODate("2019-09-20T02:00:58.254Z")
  },
  {
    "_id": "BF",
    "msg": "Undsen bichver 3",
    "ts": ISODate("2019-09-20T02:01:06.784Z")
  },
  {
    "_id": "Jq",
    "msg": "Undsen bichver 4",
    "ts": ISODate("2019-09-20T02:01:11.785Z")
  }
]

Проверьте код в интерактивном режиме Mongoplayground

...