Как получить документы фильтра mongodb на основе только дат, но не временных меток?

#mongodb #mongoose

#mongodb #mongoose

Вопрос:

Я работаю над функциональностью, в которой мне нужно сохранять документы mongodb между датами.

Я вообще не хочу сравнивать временные метки, чтобы получить данные.

Вот образец данных, которые у меня есть.

Образец данных:

 /* 1 */
{
    "_id" : ObjectId("5fb266103d41cc0a686b02e8"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-16T11:44:16.443Z")
}

/* 2 */
{
    "_id" : ObjectId("5fb265fda153fb1a446bff4a"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-16T11:43:57.148Z")
}

/* 3 */
{
    "_id" : ObjectId("5fb26599e876dc2428f54ca4"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-14T11:42:17.629Z")
}

/* 4 */
{
    "_id" : ObjectId("5fb265616151552660d3799f"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-14T11:41:21.590Z")
}
  

Теперь я хочу получить документы, сохраненные на 11-14-2020 (mm-dd-yyyy format) .

Ниже приведен запрос, который я использую.

Запрос:

 mongoose.connection.db.collection('80674480738')
                                    .aggregate([
                                        {
                                            $match: {
                                                "entryDayTime": {
                                                    $lte: "2020-11-14T18:30:00.000Z",
                                                    $gte: "2020-11-14T18:30:00.000Z"
                                                }
                                            }
                                        },{
                                            $sort:{"_id":-1}
                                        }
                                    ]).toArray();
  

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

 {
    "_id" : ObjectId("5fb26599e876dc2428f54ca4"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-14T11:42:17.629Z")
},
{
    "_id" : ObjectId("5fb265616151552660d3799f"),
    "projectId" : "80674480738",
    "hum" : 20,
    "temp" : 40,
    "deviceId" : "DEV-1",
    "entryDayTime" : ISODate("2020-11-14T11:41:21.590Z")
}
  

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

Итак, теперь я хочу только сравнить dates but not timestamps , чтобы получить результат.

Есть ли какой-нибудь способ сделать это?

Ответ №1:

Условие "entryDayTime": { $lte: "2020-11-14T18:30:00.000Z", $gte: "2020-11-14T18:30:00.000Z" } означает, что вы выбираете документ точно и только в "2020-11-14T18:30:00.000Z"

Попробуйте

 {
   $match: {
      "entryDayTime": {
          $lte: ISODate("2020-11-14T23:59:59.999Z"),
          $gte: ISODate("2020-11-14T00:00:00.000Z")
       }
   }
}
  

Или вы могли бы использовать moment.js библиотека:

 {
   $match: {
      "entryDayTime": {
          $lte: moment("2020-11-14T18:30:00.000Z").endOf('day').toDate(),
          $gte: moment("2020-11-14T18:30:00.000Z").startOf('day').toDate()
       }
   }
}
  

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

1. Я попробовал 2-й подход, но результат не возвращается, и временные метки выглядят одинаково, @Wernfried Domscheit

2. Невозможно ли выполнять поиск только по датам?

3. Это значения, которые я напечатал на консоли, entryDayTime: { '$lte': 2020-11-15T18:30:00.000Z, '$gte': 2020-11-15T18:30:00.000Z }

4. "2020-11-15T18:30:00.000Z" является строкой — вы должны сравнивать Date объекты со значениями даты .

5. Вы имеете в виду $lte: moment("2020-11-14").endOf('day').toDate(), $gte: moment("2020-11-14").startOf('day').toDate() ?

Ответ №2:

Это может быть экзотическим способом, но должно сработать

 .aggregate([
  { 
    "$set": {
      "entryDate": { 
        "$toDate": {
          "$subtract": [
            { "$toLong": "$entryDayTime" },
            { "$mod": [ { "$toLong": "$entryDayTime" }, 86400 * 1000] }
          ]
        }
      }
    } 
  },
  {
    "$match": {
      "entryDate": ISODate("2020-11-14")
    }
  },
  {
    "$sort": {
      "_id": 1
    }
  }
]);
  

На первом этапе будет создано новое entryDate поле.

На втором этапе будут отфильтрованы те записи, которые имеют соответствие entryDate .

На третьем этапе будет произведена сортировка записей по _id .

Это не так просто, как приведенный ниже запрос, но должно работать.

 .find({
  "entryDayTime": {
    "$gte": ISODate("2020-11-14"),
    "$lt": ISODate("2020-11-15")
  }
}).sort({
  "_id": 1
});
  

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

1. Спасибо @Andrew Неясно. Так работает ли 2-й подход? Или я должен использовать 1-й для сравнения только с датами?

2. @Aravind обе работы работают для меня. Я бы использовал первый, только если мне нужно добавить больше этапов агрегации.