MongoDB Запрос уникальных значений по другим полям - PullRequest
0 голосов
/ 20 января 2020

td; rd

Я хочу получить все транзакции и игнорировать транзакции, в которых поле pendingTransactionId равноactionId другого документа .


У меня есть коллекция под названием Транзакции, и я храню документы, которые представляют транзакции, такие как транзакции Банка. Эти транзакции имеют флаг, который сообщает вам, ожидает ли он, и поле, в котором хранится идентификатор ожидающей транзакции. Вот пример:

// Pending Transaction
{
  transactionId: 1,
  pending: true,
  pendingTransactionId: null,
  amount: 5
}

// Processed transaction
{
  transactionId: 2,
  pending: false,
  pendingTransactionId: 1,
  amount: 7
}

Это «одинаковые» транзакции, но у меня есть 2 записи о них, потому что обработанная может быть обработана в другое время (например, через 1 или 2 дня после выполнения отложенной транзакции). ), и есть поля, которые могут измениться, например amount (например, это может быть подсказка, которую я оставил в ресторане).

Запрос, который я пытаюсь создать, и мне трудно это та, которая выдаст мне все транзакции, но она будет игнорировать «дубликаты»: должна игнорировать транзакцию, если pendingTransactionId равен транзакции другого документа.


ОБНОВЛЕНИЕ

Добавление примера записей против ожидаемых

// records
{
  transactionId: 123,
  pending: true,
  pendingTransactionId: null,
  amount: 5
}
{
  transactionId: 321,
  pending: false,
  pendingTransactionId: 123,
  amount: 7
}
{
  transactionId: 333,
  pending: false,
  pendingTransactionId: 888,
  amount: 22
}
{
  transactionId: 444,
  pending: true,
  pendingTransactionId: null,
  amount: 50
}
{
  transactionId: 555,
  pending: false,
  pendingTransactionId: null,
  amount: 60
}
// expected
{
  transactionId: 321,
  pending: false,
  pendingTransactionId: 123,
  amount: 7
}
{
  transactionId: 333,
  pending: false,
  pendingTransactionId: 888,
  amount: 22
}
{
  transactionId: 444,
  pending: true,
  pendingTransactionId: null,
  amount: 50
}
{
  transactionId: 555,
  pending: false,
  pendingTransactionId: null,
  amount: 60
}

Запись с transactionId=123 игнорируется, поскольку уже есть обработанная транзакция (pending = false). transactionId=333 не игнорируется, поскольку не ожидает обработки, даже если у нас нет записи об ожидающей транзакции

Ответы [ 2 ]

0 голосов
/ 21 января 2020

Я хочу получить все транзакции и игнорировать транзакции, в которых поле pendingTransactionId равно транзакции другого документа.

Это операция self lookup, Находит все транзакции, которые имеют родительскую транзакцию (транзакция с pendingTransactionId), как массив результатов для каждого документа. Затем удалите все документы с родительской транзакцией на следующем этапе. В примерах документов transactionId: 123 имеет соответствие с родителем transactionId: 321.

db.test.aggregate( [
 {
    $lookup: {
        from: "txns",
        localField: "transactionId",
        foreignField: "pendingTransactionId",
        as: "parent_txn"
    }
 },
 {
    $match: { parent_txn: { $size: 0 } }
 },
 { 
    $project: { parent_txn: 0 }
 }
] )
0 голосов
/ 21 января 2020

Нет собственного решения ...

  1. Однако мы можем создать left join с самим собой с помощью оператора $lookup, сопоставляя документы путем объединения transactionId и * 1007. * поля

Мы можем получить:

a) doc{ pending = false, transaction : [{pending: true}]  } ✔
b) doc{ pending = true,  transaction : [{pending: false}] } X
c) doc{ pending = false, transaction : []               } ✔

На следующем этапе мы фильтруем документы с помощью внутреннего массива transaction.pending = true или пустого transaction.

При $ unset мы исключаем поле из результирующего документа.


db.collection.aggregate([
  {
    $lookup: {
      from: "collection",
      let: {
        transactionId: "$transactionId",
        pendingTransactionId: "$pendingTransactionId"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $or: [
                {
                  $eq: [
                    "$$transactionId",
                    "$pendingTransactionId"
                  ]
                },
                {
                  $eq: [
                    "$transactionId",
                    "$$pendingTransactionId"
                  ]
                }
              ]
            }
          }
        }
      ],
      as: "transactions"
    }
  },
  {
    $match: {
      $expr: {
        $or: [
          {
            $eq: [
              {
                $let: {
                  vars: {
                    transaction: {
                      $arrayElemAt: [
                        "$transactions",
                        0
                      ]
                    }
                  },
                  in: "$$transaction.pending"
                }
              },
              true
            ]
          },
          {
            $eq: [
              {
                $size: "$transactions"
              },
              0
            ]
          }
        ]
      }
    }
  },
  {
    $unset: "transactions"
  }
])

MongoPlayground

...