Группировать массив документов по последовательности: MongoDB groupby или mapreduce? - PullRequest
1 голос
/ 11 июля 2019

В mongodb у меня есть коллекция документов с массивом записей, которые я хочу сгруппировать по похожим тегам, сохраняя естественный порядок

    {
            "day": "2019-01-07",
            "records": [
                {
                    "tag": "ch",
                    "unixTime": ISODate("2019-01-07T09:06:56Z"),
                    "score": 1
                },
                {
                    "tag": "u",
                    "unixTime": ISODate("2019-01-07T09:07:06Z"),
                    "score": 0
                },
                {
                    "tag": "ou",
                    "unixTime": ISODate("2019-01-07T09:07:06Z"),
                    "score": 0
                },
                {
                    "tag": "u",
                    "unixTime": ISODate("2019-01-07T09:07:20Z"),
                    "score": 0
                },
                {
                    "tag": "u",
                    "unixTime": ISODate("2019-01-07T09:07:37Z"),
                    "score": 1
                }
         ]

Я хочу сгруппировать (и агрегировать) записи по аналогичной последовательности тегов, а НЕ просто путем группировки уникальных тегов

Желаемый вывод:

    {
            "day": "2019-01-07",
            "records": [
                {
                    "tag": "ch",
                    "unixTime": [ISODate("2019-01-07T09:06:56Z")],
                    "score": 1
                    "nbRecords": 1
                },
                {
                    "tag": "u",
                    "unixTime": [ISODate("2019-01-07T09:07:06Z")],
                    "score": 0,
                    "nbRecords":1
                },
                {
                    "tag": "ou",
                    "unixTime": [ISODate("2019-01-07T09:07:06Z")],
                    "score": 0
                },
                {
                    "tag": "u",
                    "unixTime: [ISODate("2019-01-07T09:07:20Z"),ISODate("2019-01-07T09:07:37Z")]
                    "score": 1
                    "nbRecords":2
                }
         ]

GroupBy

Похоже, что оператор агрегации $ groupby в mongodb ранее сортировал массив и группу по уникальному полю

   db.coll.aggregate(
         [
           {"$unwind":"$records"},
           {"$group":
                   {
                       "_id":{ 
                           "tag":"$records.tag",
                           "day":"$day"
                        },
                       ...
                    }
            }
         ]
   )

Возвращает

{
            "day": "2019-01-07",
            "records": [
                {
                    "tag": "ch",
                    "unixTime": [ISODate("2019-01-07T09:06:56Z")],
                    "score": 1
                    "nbRecords": 1
                },
                {
                    "tag": "u",
                    "unixTime": [ISODate("2019-01-07T09:07:06Z"),ISODate("2019-01-07T09:07:20Z"),ISODate("2019-01-07T09:07:37Z")],
                    "score": 2,
                    "nbRecords":3
                },
                {
                    "tag": "ou",
                    "unixTime": [ISODate("2019-01-07T09:07:06Z")],
                    "score": 0
                },

         ]

Карта / уменьшить

Поскольку в настоящее время я использую драйвер pymongo, я реализовал решение обратно в python. используя itertools.groupby, который в качестве генератора выполняет группировку в соответствии с естественным порядком, но я сталкиваюсь с проблемой тайм-аута сервера (cursor.NotFound Error) в качестве безумной обработки времени.

Любая идея о том, как напрямую использовать функцию mapreduce mongo выполнить эквивалент itertools.groupby() в python?

Помощь была бы очень признательна: я использую драйвер pymongo 3.8 и MongoDB 4.0

Ответы [ 2 ]

0 голосов
/ 13 июля 2019

С рекомендацией @Ale и без каких-либо советов, как это сделать в MongoDb. Я переключаюсь обратно на реализацию Python, решающую проблему курсора. Не найдена.

Я полагаю, что я мог бы закончить в Mongodb, но это работает

for r in db.coll.find():
        session = [

        ]
        for tag, time_score in itertools.groupby(r["records"], key=lambda x:x["tag"]):
            time_score = list(time_score)
            session.append({
                "tag": tag, 
                "start": time_score[0]["unixTime"], 
                "end": time_score[-1]["unixTime"], 
                "ca": sum([n["score"] for n in time_score]), 
                "nb_records": len(time_score) 
            })
        db.col.update(
                {"_id":r["_id"]}, 
                {
                    "$unset": {"records": ""},
                    "$set":{"sessions": session}
                })
0 голосов
/ 12 июля 2019

Ni!Просмотрите массив записей, добавив новый целочисленный индекс, который увеличивается всякий раз, когда изменяется цель groupby, затем используйте операцию mongo для этого индекса.. ~

...