Устранить дубликаты в MongoDB с указанием c сортировки - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть база данных, составленная из записей, которые соответствуют трудовым договорам. В базе данных MongoDB я агрегировал по параметру c worker, затем база данных - в упрощенной версии - выглядит примерно так.

{
    "_id" : ObjectId("5ea995662a40c63b14266071"),
    "worker" : "1070",
    "employer" : "2116096",
    "start" : ISODate("2018-01-11T01:00:00.000+01:00"),
    "ord_id" : 0
},
{
    "_id" : ObjectId("5ea995662a40c63b14266071"),
    "worker" : "1070",
    "employer" : "2116096",
    "start" : ISODate("2018-01-11T01:00:00.000+01:00"),
    "ord_id" : 1
},
{
    "_id" : ObjectId("5ea995662a40c63b14266072"),
    "worker" : "1071",
    "employer" : "2116055",
    "start" : ISODate("2019-01-03T01:00:00.000+01:00"),
    "ord_id" : 2
},
{
    "_id" : ObjectId("5ea995662a40c63b14266072"),
    "worker" : "1071",
    "employer" : "2116056",
    "start" : ISODate("2019-01-03T01:00:00.000+01:00"),
    "ord_id" : 3
},

Я переставил на основе рабочих

{
    "_id" : ObjectId("5ea995662a40c63b14266071"),
    "worker" : "1070",
    "contratcs" : [
             {
               "employer" : "2116096",
               "start" : ISODate("2018-01-11T01:00:00.000+01:00"),
               "ord_id" : 0
             },
             {
               "employer" : "2116096",  
               "start" : ISODate("2018-01-11T01:00:00.000+01:00"),
               "ord_id" : 1
             } // Since employer identification and starting date is the same of the previous, this is a duplicate!
         ]
},
{
    "_id" : ObjectId("5ea995662a40c63b14266072"),
    "worker" : "1701",
    "contratcs" : [
             {
               "employer" : "2116055",
               "start" : ISODate("2019-01-03T01:00:00.000+01:00"),
               "ord_id" : 2
             },
             {
               "employer" : "2116056",
               "start" : ISODate("2019-01-04T01:00:00.000+01:00"),
               "ord_id" : 3
             }
         ]
}

Из первоначальной таблицы некоторые контракты были проверены дважды, поэтому я должен сохранить только один. Более конкретно (в примере), я считаю дубликаты тех контрактов (для одного и того же работника), начатых в тот же день и с одним и тем же работодателем. Однако должен быть правильный выбор, какой дубликат сохранить, а какой нет (это не зависит от меня). По существу, есть поле с именем 'ord_id' (я сгенерировал генерацию базы данных в MongoDB), которое является числом и является уникальным (следовательно, среди дубликатов это единственный термин, который фактически отличается). По сути, я должен сохранить среди дубликатов те, которые имеют наибольшее значение 'ord_id'. Следуя этой теме, я написал:

db.mycollection.aggregate([
    { $unwind: "$contracts" },
    { $group: {
        _id: { WORKER: "$worker", START: "$contracts.start" },
        dups: { $addToSet: "$_id" },
        ord_id: { $addToSet: "$contracts.ord_id" },
        count:  {$sum: 1 }
        }
    },
    { $match: { count: { $gt: 1} } },
    { $sort: {count: -1, ord_id: -1 } }
],{allowDiskUse: true}).
forEach(function(doc) {
    doc.dups.shift();     
    db.mycollection.remove({_id : {$in: doc.dups }});  
});

Несмотря на то, что у меня возникают проблемы с устранением, когда я агрегирую по контрактам, я хотел бы сместить (затем сохранить) дубликаты тот, который имеет наибольшее значение 'ord_id'. Я все еще новичок в MongoDB и все еще нахожусь в фазе умственного перехода от подхода, в основном относительного (SQL). Извиняюсь за глупый вопрос.

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Эта агрегация вернет желаемый результат - устраняет дубликат на основе работника + работодателя + старт contracts и сохраняет только контракт с самым высоким ord_id (из дубликатов).

db.collection.aggregate( [
  { 
      $unwind: "$contracts" 
  },
  { 
      $group: { 
           _id: { worker: "$worker", employer: "$contracts.employer", start: "$contracts.start" },
           max_ord: { $max: "$contracts.ord_id" },
           doc: { $first: "$$ROOT" }
      } 
  },
  { 
      $group: {
          _id: { _id: "$doc._id", worker: "$doc.worker" },
          contracts: { $push: { employer: "$_id.employer", start: "$_id.start", ord_id: "$ords" } }
      }
  },
  { 
      $addFields: {
          _id: "$_id._id", 
          worker: "$_id.worker"
      }
  } 
] )
1 голос
/ 29 апреля 2020

Если вы выполните обратную сортировку по ord_id, вы можете использовать $first на этапе $group, чтобы выбрать наибольшее значение. Этот пример вернет весь документ в doc, а также количество дубликатов:

db.mycollection.aggregate([
    { $unwind: "$contracts" },
    { $sort: {"$contracts.ord_id":-1}},
    { $group: {
        _id: { WORKER: "$worker", START: "$contracts.start", EMPLOYER: "$contracts.employer" },
        doc: { $first: "$$ROOT" },
        count:  {$sum: 1 }
    }}
],{allowDiskUse: true})
...