Как я могу выполнить многоуровневую агрегацию ad-ho c на основе фильтров, предоставленных пользователем? - PullRequest
0 голосов
/ 30 марта 2020

Моя схема документа выглядит примерно так:

{
  name: "John Doe",
  City : "OK",
  Prepaid: "Y",
  Ethnicity: 'a',
  Zip: '06516'
},
{
  name: "Jane Doe",
  City : "CA",
  Prepaid: "N",
  Ethnicity: 'b'
  Zip: '12321'
},
{
  name: "Jule Doe",
  City : "OK",
  Prepaid: "N",
  Ethnicity: 'a'
  Zip: '06516'
},
{
  name: "Jake Doe",
  City : "OK",
  Prepaid: "Y",
  Ethnicity: 'a',
  zip: '06516'
}

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

То, что я хочу получить, будет выглядеть примерно так:

Если пользователь выберет группировать их по городам и предоплате, то это будет выглядеть так:

{
  City : OK
  Count : {
    "filter": prepaid,
    "count": {
      Y : 2
      N: 1
    }
  }
}

{
  City : CA
  Count : {
    "filter": prepaid,
    "count": {
      Y : 0
      N: 1
    }
  }
}

Но если пользователь выберет Этническая принадлежность и Предоплата, это будет выглядеть примерно так:

{

      Ethinicity : A,
      City: OK
      Count : {
        "filter": prepaid,
        "count": {
          Y : 2
          N: 1
        }
      }
    }

{

      Ethinicity : B,
      City: CA
      Count : {
        "filter": prepaid,
        "count": {
          Y : 1
          N: 0
        }
      }
    }

Я попытался сделать это:

const countVals = await PhoneSamplingCollection.aggregate([
                        { $match: fullQuery },
                        {$group: groupquery //variable that has object provided by user to group on
                         , count:{$sum:1}}}
                    ]).exec();

Это дает мне только счет вместе, а не разбивку.

1 Ответ

0 голосов
/ 30 марта 2020

Вы можете попробовать выполнить запрос ниже:

Обновленный ответ:

Если в поле Предоплата есть несколько вариантов для группировки, тогда попробуйте следующий запрос:

db.collection.aggregate([
  /** Group on city & prepaid & count no.of docs matches each criteria */
  {
    $group: { _id: { City: "$City", Prepaid: "$Prepaid" }, Count: { $sum: 1 } }
  },
  /** Group only on City to push all data to a field Count */
  {
    $group: {
      _id: "$_id.City",
      Count: { $push: { k: "$_id.Prepaid", v: "$Count" } }
    }
  },
  /** Transform fields using project stage &
   *  use 'arrayToObject' to convert count array of objects to an object with {k:...,v:...} */
  { $project: { _id: 0, City: "$_id", Count: { $arrayToObject: "$Count" } } },
  { $project: { City: 1, Count: { count: "$Count", filter: "Prepaid" } } }
]);

Тест: MongoDB-Playground

Старый ответ:

db.collection.aggregate([
  {
    $group: {
      _id: "$City",
      Y: { $sum: { $cond: [{ $eq: ["$Prepaid", "Y"] }, 1, 0] } },
      N: { $sum: { $cond: [{ $eq: ["$Prepaid", "N"] }, 1, 0] } }
    }
  },
  {
    $project: {
      _id: 0,
      City: "$_id",
      Count: { filter: "Prepaid", count: { Y: "$Y", N: "$N" } }
    }
  }
]);

Тест: MongoDB-Playground

Таким образом, в вашем коде вы будете строить запросы на основе выбора пользователя и переключаться между ними в зависимости от условий. Проверьте ниже запрос, если вам нужно Ethinicity.

db.collection.aggregate([
  {
    $group: {
      _id: {
        City: "$City",
        Ethnicity: "$Ethnicity"
      },
      Y: { $sum: { $cond: [{ $eq: ["$Prepaid", "Y"] }, 1, 0] } },
      N: { $sum: { $cond: [{ $eq: ["$Prepaid", "N"] }, 1, 0] } }
    }
  },
  {
    $project: {
      _id: 0,
      City: "$_id.City",
      Ethnicity: "$_id.Ethnicity",
      Count: { filter: "Prepaid", count: { Y: "$Y", N: "$N" } }
    }
  }
]);

Тест: MongoDB-Playground

...