Используйте MongoDB ObjectId для группировки по дате (ymd) и уникальному IP в день

#mongodb #aggregation-framework

#mongodb #платформа агрегации

Вопрос:

Ввод:

 {_id:ObjectID(123),ip:'123.123.123.123'}
{_id:ObjectID(123),ip:'123.123.123.123'}
{_id:ObjectID(124),ip:'123.123.123.124'}
{_id:ObjectID(125),ip:'123.123.123.125'}
  

Вывод:

 {2019-03-20: 1}
{2019-03-21: 1}
{2019-03-22: 1}
  

Я возился с этим весь день, чтобы извлечь временную метку из идентификатора mongo и использовать ее для ежедневного отдельного подсчета IP-адресов, но у меня ничего не получается… В итоге я всегда получаю количество IP-адресов, так как IP в день X был найден 4 раза… не уникальные IP-адреса в день X.

Спасибо!

Ответ №1:

Вы можете использовать $ToDate и $dateToString для получения даты из ObjectId , а затем использовать $ addToSet для получения уникальных IP-адресов за день. На последнем шаге вам понадобится $ size, чтобы получить длину ip массива:

 db.collection.aggregate([
    {
        $group: {
            _id: { $dateToString: { date: { $toDate: "$_id" }, format: '%Y-%m-%d' } },
            ip: { $addToSet: "$ip" }
        }
    },
    {
        $project: {
            _id: 0,
            date: "$_id",
            ipCount: { $size: "$ip" }
        }
    }
])
  

Комментарии:

1. это было быстро: D — итак, здесь одна проблема compose.com использует MongoDB 3.6.8 и говорит, что не существует ни $ ToDate, ни $ convert :/

2. @Toby Боюсь, вам нужно обновить до 4.0 или предварительно обработать ваши документы и добавить поле ISODate. Вы можете сделать это в оболочке Mongo docs.mongodb.com/manual/reference/method/ObjectId.getTimestamp

3. на самом деле не могу обновиться, поскольку это не в моих силах с compose.com и на самом деле не может изменить данные… Я пробовал использовать getTimestamp, но, похоже, ничего не вышло

4. @Toby вам нужен скрипт для добавления нового поля типа ISODate — это, кажется, самый простой обходной путь для MongoDB < 4.0

5. не могли бы вы просто выполнить getTimestamp() из _id и поработать с этим? если вы можете записать это в базу данных, вы можете прочитать это, нет?

Ответ №2:

В MongoDB версии v3.8 нижеприведенное работает — все благодаря @mickl

 db.getCollection('data').aggregate([
    {
        $group: {
            "_id" : {
                "$dateToString": {
                    "format": "%Y-%m-%d",
                    "date": "$_id"
                }
            },
            "ip": { $addToSet: "$ip" }
        }
    },
    {
        $project: {
            _id: 0,
            date: "$_id",
            ipCount: {
                $size: "$ip"
            }
        }
    },
    {
        $sort: {
            date: -1
        }
    }
]);