MongoDB вернет счетчик 0 для полей пропущенных месяцев - PullRequest
1 голос
/ 02 апреля 2020

У меня есть этот запрос mongodb, который возвращает количество преступлений, связанных с похищением людей за месяц, он основывает номер месяца, например, 1, затем, если он совпадает с 1, он подсчитывает результат и возвращает количество записей.

exports.getAllCarnappingRecords = function(callback)
{
crimes.aggregate([{
    $facet: {
        1: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 1 } }, { $count: "1" } ],
        2: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 2 } }, { $count: "2" } ],
        3: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 3 } }, { $count: "3" } ],
        4: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 4 } }, { $count: "4" } ],
        5: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 5 } }, { $count: "5" } ],
        6: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 6 } }, { $count: "6" } ],
        7: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 7 } }, { $count: "7" } ],
        8: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 8 } }, { $count: "8" } ],
        9: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 9 } }, { $count: "9" } ],
        10: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 10 } }, { $count: "10" } ],
        11: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 11 } }, { $count: "11" } ],
        12: [ { $match: { crimetype: 'Carnapping' } }, { $project: { month: {$month: '$date_happened'} } }, { $match: { month: 12 } }, { $count: "12" } ],
    }
}]).toArray(
    function(e, res) {
    if (e) callback(e)
    else callback(null, res)
});
}

возвращает это по маршруту.

[{"1":[{"1":2}],"2":[{"2":1}],"3":[{"3":1}],"4":[{"4":1}],"5":[{"5":1}],"6":[{"6":1}],"7":[{"7":1}],"8":[{"8":5}],"9":[{"9":1}],"10":[{"10":1}],"11":[{"11":1}],"12":[{"12":1}]}]

Чтобы объяснить это далее, {"1": [{"1": 2}], где первая 1 - это запрос № 1, а следующий 1 указывает на январь как 1-й месяц года. и, наконец, 2, которое указывает число преступлений в январе.

Но когда записи пустые, возвращается ошибка "TypeError: Cannot read property '1' of undefined". Вместо того, чтобы возвращать ошибку, я хочу получить сообщение об ошибке. вместо этого получит результат 0.

[{"1":[{"1":0}],"2":[{"2":0}],"3":[{"3":0}],"4":[{"4":0}],"5":[{"5":0}],"6":[{"6":0}],"7":[{"7":0}],"8":[{"8":0}],"9":[{"9":0}],"10":[{"10":0}],"11":[{"11":0],"12":[{"12":0}]}]

Мой входной документ выглядит следующим образом.

{
"_id" : ObjectId("5e84850262622854228097ab"),
"name" : "kokookokoaaa",
"location" : "kokookoko",
"crimetype" : "Carnapping",
"date_happened" : ISODate("2019-08-30T10:00:00.000Z"),
"description" : "kokookoko",
"record_created" : "April 1st 2020, 8:11:46 pm"
}

1 Ответ

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

Как я уже говорил в комментариях: вы выполняете одну и ту же операцию несколько раз !! Каждый раз, когда он должен go пройти через целые документы, где 'crimetype:' Carnapping '' - это может ужасно go неправильно с огромными наборами данных Вместо $facet вы можете попробовать запрос ниже.

Запрос:

db.collection.aggregate([
  /** Retrive docs whose 'crimetype' equals to "Carnapping" */
  { $match: { crimetype: "Carnapping" } },
  /** Group on month & count no.of occurances */
  { $group: { _id: { $month: "$date_happened" }, count: { $sum: 1 } } },
  /** Max docs after above group stage will be 12,
   *  & now Group all docs into single doc, push everything to 'monthsAndCount' field*/
  {
    $group: {
      _id: "",
      monthsAndCount: { $push: { month: "$_id", count: "$count" } }
    }
  },
  /** Transform fields & as few months are missing add their respective 'count' field value as 0 */
  {
    $project: {
      _id: 0,
      monthsAndCount: {
        /** After reduce 'monthsAndCount' array field will have all month & respective count */
        $reduce: {
          input: {
            $setDifference: [
              // Difference will be missing months
              [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // All months
              "$monthsAndCount.month" // Existing
            ]
          },
          initialValue: "$monthsAndCount",
          in: {
            $concatArrays: [
              [
                {
                  month: "$$this",
                  count: 0
                }
              ],
              "$$value"
            ]
          }
        }
      }
    }
  },
  /** Here on all are optional stages, As you need data clubed & 
    * result to be in the form of '[2,1,2,1,1,1,1,1,1,1,1,1]' */
  /** unwind 'monthsAndCount' array field */
  {
    $unwind: "$monthsAndCount"
  },
  /** Sort on month to keep docs in order based on months */
  {
    $sort: {
      "monthsAndCount.month": 1
    }
  },
  /** Group on all 12 docs & push count to data field */
  {
    $group: {
      _id: "",
      data: {
        $push: "$monthsAndCount.count"
      }
    }
  }
]);

Тест: MongoDB-Playground

...