Использование $ size и $ addToSet для сравнения нескольких массивов из одного кластера - PullRequest
0 голосов
/ 17 октября 2019

Вот пример документов, которые я запрашиваю:

ВВОД:

}
    "_id": ObjectId("2786872873872"),
    "data_shop" : {
        "records_data" : [
            {
                "artist_name" : [
                    {
                        "val" : "BEYONCE",
                    },
                ],
                "album_name" : [
                    {
                        "val" : "COUNTDOWN",
                    }
                ],
                "qty" : [
                    0,
                    1,
                    2,
                    3
                ]
            },
            {
                "artist_name" : [
                    {
                        "val" : "MUSE",
                    },
                ],
                "album_name" : [
                    {
                        "val" : "THE RESISTANCE",
                    }
                ],
                "qty" : [
                    0,
                    1,
                    2,
                    3,
                    3
                ]
            }
        ],
    },
}
}
    "_id": ObjectId("2786872855555"),
    "data_shop" : {
        "records_data" : [
            {
                "artist_name" : [
                    {
                        "val" : "MAC MILLER",
                    },
                ],
                "album_name" : [
                    {
                        "val" : "SWIMMING",
                    }
                ],
                "qty" : [
                    0,
                    1,
                    2,
                    3,
                ]
            },
            {
                "artist_name" : [
                    {
                        "val" : "DAFT PUNK",
                    },
                ],
                "album_name" : [
                    {
                        "val" : "RANDOM ACCESS MEMORIES",
                    }
                ],
                "qty" : [
                    0,
                    1,
                    2,
                    3,
                    4,
                ]
            }
        ],
    },
}

Что я сделал до сих пор:

Я пытаюсь использовать и $ size, и $ addtoSet, чтобы вернуть ObjectIds, которые имеют повторяющиеся числа в поле qty . Как видите, только первый ObjectId имеет повторяющийся номер (3) в поле qty. Это то, что я сделал до сих пор:

db.mycollection.aggregate(
    [
        {$match: {"data_shop.records_data.qty.1": {$lte: 1}}},
        {
            $project: {Album_Cluster:"$data_shop.records_data"}
        },
        {
            $unwind: "$Album_Cluster"
        },
        {
            $project: {qty: "$Album_Cluster.qty"},
        },
        {
            $project: {qty_size: {$size: "$qty"}, qty:1}
        },
        { $match: {"qty_size.1": {$exists: false}, qty_size: {$gt: 1} }},
        {$group:
            {_id: "$_id",
            totalSize: {$push: "$qty_size"},
            realSize: {$addToSet: "$qty"},
            }
        },
    ],
    {allowDiskUse: true}
)

И это результат запроса выше, чтобы проверить функциональность запроса:

{"_id":ObjectId("2786872873872"), "totalSize": [4, 5], "realSize":[[0, 1, 2, 3]]}
{"_id":ObjectId("2786872855555"), "totalSize": [4, 5], "realSize":[[0, 1, 2, 3], [0, 1, 2, 3, 4]]}

I 'Я немного застрял в этой части, так как я хочу сравнить общий размер каждого массива с реальным размером массива (под реальным размером я имею в виду неповторяющиеся числа)

OUTPUT

Вот так должен выглядеть результат запроса:

{"_id":ObjectId("2786872873872"), "isRepeating": true}
{"_id":ObjectId("2786872855555"), "isRepeating": false}

РЕДАКТИРОВАТЬ: Я улучшил свой запрос, чтобы получить следующую схему вывода:

db.mycollection.aggregate(
    [
        {$match: {"data_shop.records_data.qty.1": {$lte: 1}}},
        {
            $project: {Album_Cluster:"$data_shop.records_data"}
        },
        {
            $unwind: "$Album_Cluster"
        },
        {
            $project: {qty: "$Album_Cluster.qty"},
        },
        {
            $project: {qty_size: {$size: "$qty"}, qty:1}
        },
        {$group:
            {
            _id: "$_id",
            totalSize: {$addToSet: "$qty_size"},
            realSize: {$addToSet: "$qty"},
            }
        },
        {$unwind: "$realSize"},
        {
            $project: 
            {
                totalSize:1,
                real_count: {$size: "$realSize"}
            }
        },
        {$unwind: "$totalSize"},
        {
            $group: {
                _id: "$_id",
                total_size: {$addToSet: "$totalSize"},
                real_size: {$addToSet: "$real_count"}
            }
        },
    ],
    {allowDiskUse: true}
)

И теперь я получаю это как вывод:

{"_id":ObjectId("2786872873872"), "total_size": [4, 5], "real_size":[4]}
{"_id":ObjectId("2786872855555"), "total_size": [4, 5], "real_size":[5, 4]}

Теперь мой вопрос: $in позволяет мне проверить, что [4, 5] действительно в[5, 4], поэтому мой вывод будет isRepeating = false?

1 Ответ

0 голосов
/ 17 октября 2019

Хотя вы можете достичь этого с помощью стека или групповых этапов, это может быть очень дорого в потреблении ресурсов. К сожалению, оператор $ addToSet доступен только на этапе $ group.

Но ... Есть хитрость с оператором $ setUnion .

$setUnion выполняет операции над множествами, рассматривая массивы как множества. Если массив содержит повторяющиеся записи, $ setUnion игнорирует дублирующиеся записи.

Зная это, выполнение $ setUnion для вашего массива qty без какого-либо другого массива просто ... удалит дубликаты.

Вот реализация этого подхода, использующая только 2 этапа проекта

db.collection.aggregate([
  {
    $project: {
      "data_shop.records_data": {
        $map: {
          input: "$data_shop.records_data",
          as: "data",
          in: {
            qty_size: {
              $size: "$$data.qty"
            },
            qty_size_unique: {
              $size: {
                $setUnion: [
                  "$$data.qty"
                ]
              }
            }
          }
        }
      }
    }
  },
  {
    $project: {
      isRepeating: {
        $cond: {
          if: {
            $eq: [
              "$data_shop.records_data.qty_size",
              "$data_shop.records_data.qty_size_unique"
            ]
          },
          then: false,
          else: true
        }
      }
    }
  }
])

Он вернет ожидаемый результат:

[
  {
    "_id": 1,
    "isRepeating": true
  },
  {
    "_id": 2,
    "isRepeating": false
  }
]
...