Или инструкция возвращает только первый результат (должно быть 2)

#mongodb #aggregate

Вопрос:

У меня есть оператор OR, в котором ожидаемый результат должен возвращать 2 документа, но возвращаемый результат-только 1 документ. У меня есть список документов по автомобилям:

 [
  {
    "_id": ObjectId("60a2c0621e5f043b735e36ef"),
    "car_id": 78,
    "terminal": "JFK",
    "timestamp": ISODate("2020-01-01T17:00:00.000Z"),
    
  },
  {
    "_id": ObjectId("60a2c0621e5f043b735e36f0"),
    "car_id": 78,
    "terminal": "LAX",
    "timestamp": ISODate("2020-02-08T17:00:00.000Z"),
    
  },
  {
    "_id": ObjectId("60a2c0621e5f043b735e36f1"),
    "car_id": 78,
    "terminal": "ORD",
    "timestamp": ISODate("2020-03-01T17:00:00.000Z"),
    
  },
]
 

и мой запрос запрашивает 2 экземпляра с ОДИНАКОВЫМ идентификатором АВТОМОБИЛЯ, но с РАЗНОЙ отметкой времени:

 db.collection.aggregate([
  {
    "$match": {
      "$or": [
        {
          "car_id": 78,
          "timestamp": {
            "$lte": ISODate("2020-02-15T05:00:11.000Z")
          }
        },
        {
          "car_id": 78,
          "timestamp": {
            "$lte": ISODate("2020-03-02T11:07:27.000Z")
          }
        }
      ]
    }
  },
  {
    "$sort": {
      "timestamp": 1
    }
  },
  {
    "$group": {
      "_id": "$car_id",
      "last": {
        "$last": "$ROOT"
      }
    }
  }
])
 

Поэтому я ожидаю получить 2 результата (для каждого запроса).

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

 [
  {
    "_id": 78,
    "last": {
      "_id": ObjectId("60a2c0621e5f043b735e36f1"),
      "car_id": 78,
      "terminal": "ORD",
      "timestamp": ISODate("2020-03-01T17:00:00Z")
    }
  },

  {
    "_id": 78,
    "last": {
      "_id": ObjectId("60a2c0621e5f043b735e36f0"),
      "car_id": 78,
      "terminal": "LAX",
      "timestamp": ISODate("2020-02-08T17:00:00Z")
    }
  }
]
 

Но я получаю только первый результат. Как я могу получить желаемые 2 результата?

mongoplayground

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

1. Уважаемый ПроколХарум, рекомендуется, чтобы вопрос содержал всю необходимую информацию в самом вопросе. Хотя mongoplayground-удивительный сервис и очень помогает, не было очевидно, что вы также группируете результаты.

2. @AlexBlex хорошо понял. Я вижу, что вы его добавили. Спасибо

Ответ №1:

Потому что все возвращенные документы одинаковы car_id , и вы используете car_id их на $group этапе, поэтому они будут сгруппированы в один результат. Чтобы получить ожидаемый результат, вы можете добавить поле в зависимости от метки времени документа, а затем использовать его в $group :

 db.collection.aggregate([
  {
    "$match": {
      "$or": [
        {
          "car_id": 78,
          "timestamp": {
            "$lte": ISODate("2020-02-15T05:00:11.000Z")
          }
        },
        {
          "car_id": 78,
          "timestamp": {
            "$lte": ISODate("2020-03-02T11:07:27.000Z")
          }
        }
      ]
    }
  },
  {
    "$sort": {
      "timestamp": 1
    }
  },
  {
    $addFields: {
      group: {
        $cond: {
          if: {
            $lte: [
              "$timestamp",
              ISODate("2020-02-15T05:00:11.000Z")
            ]
          },
          then: 1,
          else: 2
        }
      }
    }
  },
  {
    "$group": {
      "_id": "$group",
      "last": {
        "$last": "$ROOT"
      }
    }
  }
])
 

Mongoplayground

Примечание: Если в результате у вас более одного car_id , вы можете изменить значение $group на:

 {
  "$group": {
    "_id": {
      car_id: "$car_id",
      group: "$group",
    },
    "last": {
      "$last": "$ROOT"
    }
  }
}
 

Mongoplayground