MongoDB - Как рассчитать поле на основе существования других полей? - PullRequest
0 голосов
/ 05 февраля 2020

Предположим, у меня есть коллекция trips, где я хотел бы вычислить status каждого trip. Состояние рассчитывается на основе других полей.

  • Если в поездке нет водителя, оно должно быть pending.
  • Если в поездке есть водитель, оно должно быть in transit.
  • Если в поездке есть водитель и номер счета, то он должен быть completed.
  • Если в поездке есть водитель, номер счета и номер счета, он должен быть billed.

Как я могу реализовать это с помощью конвейера агрегации?

Примеры документов:

[{
    // This has both driver and invoice, should be completed
    "_id" : ObjectId("5e24fbfd44621900c5730a48"),
    "customer" : ObjectId("5dd7eaf7ef8a7b00ba8f090b"),
    "date" : ISODate("2020-01-17T03:00:00.000Z"),
    "distance" : 24, // in km
    "driver" : ObjectId("5e1e302e26f00000c451923e"),
    "invoice" : "0001-00001234",
    "status": "completed" // this should be calculated

},
{
    // This has only driver, should be in transit
    "_id" : ObjectId("5e24fbfd44621900c5730a48"),
    "customer" : ObjectId("5dd7eaf7ef8a7b00ba8f090b"),
    "date" : ISODate("2020-01-17T03:00:00.000Z"),
    "distance" : 24, // in km
    "driver" : ObjectId("5e1e302e26f00000c451923e"),
    "status": "in transit" // this should be calculated

},
{
    // This is missing both driver and invoice, should be pending
    "_id" : ObjectId("5e24fbfd44621900c5730a48"),
    "customer" : ObjectId("5dd7eaf7ef8a7b00ba8f090b"),
    "date" : ISODate("2020-01-17T03:00:00.000Z"),
    "distance" : 24, // in km
    "status": "pending" // this should be calculated
}]

Ответы [ 2 ]

1 голос
/ 05 февраля 2020

Вы можете попробовать это, он использует $ switch для проверки всех случаев в серии & $ type для проверки существования поля:

db.trips.aggregate([{
    $addFields: {
        status: {
            $switch:
            {
                branches: [
                    {
                        case: { $eq: [{ $type: '$driver' }, 'missing'] },
                        then: 'pending'
                    },
                    {
                        case: { $eq: [{ $type: '$driver' }, 'objectId'] },
                        then: 'in transit'
                    },
                    {
                        case: {
                            $and: [{ $eq: [{ $type: '$driver' }, 'objectId'] },
                            { $eq: [{ $type: '$invoice' }, 'string'] }]
                        },
                        then: "completed"
                    },
                    {
                        case: {
                            $and: [{ $eq: [{ $type: '$driver' }, 'objectId'] },
                            { $eq: [{ $type: '$invoice' }, 'string'] },
                            { $eq: [{ $type: '$billNumber' }, 'string'] }]
                        },
                        then: "billed"
                    }
                ],
                default: '$status'
            }
        }
    }
}
])

Ссылка: MongoDB-Playground

0 голосов
/ 05 февраля 2020

Одним из решений может быть следующее:

db.col.updateMany(
   {
      driver: { $exists: true },
      invoice: { $exists: true }
   },
   { $set: {status: "completed"}}
)

db.col.updateMany(
   {
      driver: { $exists: false },
      invoice: { $exists: false }
   },
   { $set: {status: "pending"}}
)

db.col.updateMany(
   {
      driver: { $exists: true },
      invoice: { $exists: false }
   },
   { $set: {status: "in transit"}}
)

Или в одной команде с конвейером агрегации (начиная с MongoDB 4.2):

db.col.updateMany(
   {},
   [{
      $set: {
         status: {
            $switch: {
               branches: [
                  { case: { $and: ["$driver", "$invoice"] }, then: "completed" },
                  { case: { $and: ["$driver", { $not: "$invoice" }] }, then: "in transit" },
                  { case: { $and: [{ $not: "$driver" }, { $not: "$invoice" }] }, then: "pending" },
               ],
               default: "$status"
            }
         }
      }
   }]
)
...