объединение двух стадий агрегации mongodb - PullRequest
0 голосов
/ 16 июня 2019

У меня есть ряд цен, как показано ниже в коллекции mongodb:

id date       value
A  1 Jan 18   1
A  2 Jan 18   0
A  3 Jan 18   0
B  14 Jan 18  4
B  15 Jan 18  5
B  16 Jan 18  0
C  2 Jan 18   4
C  3 Jan 18   4
C  5 Jan 18   3

Используя конвейер агрегации mongodb (mongo 3.4), я пытаюсь выяснить для каждого идентификатора, на какую дату его значение меняется с 0 на ненулевое, а также на группу id для этих записей.

У меня есть способ найти первую и последнюю дату, когда запись имеет определенное значение:

{
    "$addFields": {
      "date": {
        "$dateFromString": {
          "dateString": "$date"
        }
      }
    }
  },
  {
    $group: {
      _id: {
        "id": "$id",
        "value": "$value"
      },
      "first": {
        "$first": "$date"
      },
      "last": {
        "$last": "$date"
      }
    }
  },
  {
    "$match": {
      "_id.value": 0
    }
  }

https://mongoplayground.net/p/moBRI2Q7aGu

Это дает мне (обратите внимание, что идентификатор C отсутствует, так как он не имеет значения 0):

id value   first      last
A  0       2 Jan 18   3 Jan 18
B  0       16 Jan 18  16 Jan 18

Если я посмотрю на «первые» даты, это те даты, когда значение сначала становится 0 из ненулевого значения.

Однако я хотел бы видеть всю «группу идентификаторов» из тех значений, которые в какой-то момент времени становятся ненулевыми. Итак, мой ожидаемый результат:

id value   first      last
A  1       1 Jan 18   1 Jan 18
A  0       2 Jan 18   3 Jan 18
B  4       14 Jan 18  14 Jan 18
B  5       15 Jan 18  15 Jan 18
B  0       16 Jan 18  16 Jan 18

Чтобы получить это, мне нужно получить доступ к групповому этапу перед совпадением вышеуказанного конвейера, поэтому https://mongoplayground.net/p/YTP-NBJtO4R, и каким-то образом отфильтровать это с набором результатов из первого конвейера агрегации. Я делаю это в пандах через левое соединение с первым набором результатов, но это выглядит не элегантно.

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

1 Ответ

1 голос
/ 21 июня 2019

Я думаю, что это должно дать вам результат, который вы ищете:

db.collection.aggregate([
  {
    "$addFields": {
      "date": {
        "$dateFromString": {
          "dateString": "$date"
        }
      }
    }
  },
  {
    "$sort": {
      date: 1
    }
  },
  {
    $group: {
      _id: {
        "id": "$id",
        "value": "$value"
      },
      "first": {
        "$first": "$date"
      },
      "last": {
        "$last": "$date"
      },
      "data": {
        "$push": "$$ROOT"
      }
    }
  },
  {
    "$sort": {
      first: 1
    }
  },
  {
    "$group": {
      _id: "$_id.id",
      last_value: {
        $last: "$_id.value"
      },
      first_date_for_last_value: {
        $last: "$first"
      },
      last_date_for_last_value: {
        $last: "$last"
      },
      all_values: {
        $push: {
          id: "$$ROOT._id.id",
          value: "$$ROOT._id.value",
          first: "$first",
          last: "$last"
        }
      }
    }
  },
  {
    "$match": {
      "last_value": 0
    }
  }
])

При желании вы можете добавить этапы $ project и $ unwind, если вам нужны только данные из 'all_values'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...