Найти объекты между двумя датами MongoDB

Я играл вокруг хранения твитов внутри mongodb, каждый объект выглядит так:

{
"_id" : ObjectId("4c02c58de500fe1be1000005"),
"contributors" : null,
"text" : "Hello world",
"user" : {
    "following" : null,
    "followers_count" : 5,
    "utc_offset" : null,
    "location" : "",
    "profile_text_color" : "000000",
    "friends_count" : 11,
    "profile_link_color" : "0000ff",
    "verified" : false,
    "protected" : false,
    "url" : null,
    "contributors_enabled" : false,
    "created_at" : "Sun May 30 18:47:06 +0000 2010",
    "geo_enabled" : false,
    "profile_sidebar_border_color" : "87bc44",
    "statuses_count" : 13,
    "favourites_count" : 0,
    "description" : "",
    "notifications" : null,
    "profile_background_tile" : false,
    "lang" : "en",
    "id" : 149978111,
    "time_zone" : null,
    "profile_sidebar_fill_color" : "e0ff92"
},
"geo" : null,
"coordinates" : null,
"in_reply_to_user_id" : 149183152,
"place" : null,
"created_at" : "Sun May 30 20:07:35 +0000 2010",
"source" : "web",
"in_reply_to_status_id" : {
    "floatApprox" : 15061797850
},
"truncated" : false,
"favorited" : false,
"id" : {
    "floatApprox" : 15061838001
}

Как мне написать запрос, который проверяет созданный_кат и находит все объекты между 18:47 и 19:00? Нужно ли обновлять документы, чтобы даты сохранялись в определенном формате?

17 ответов

Решение

Запрос на диапазон дат (определенный месяц или день) в Кулинарной книге MongoDB дает очень хорошее объяснение по этому вопросу, но ниже я кое-что попробовал сам, и похоже, что он работает.

items.save({
    name: "example",
    created_at: ISODate("2010-04-30T00:00:00.000Z")
})
items.find({
    created_at: {
        $gte: ISODate("2010-04-29T00:00:00.000Z"),
        $lt: ISODate("2010-05-01T00:00:00.000Z")
    }
})
=> { "_id" : ObjectId("4c0791e2b9ec877893f3363b"), "name" : "example", "created_at" : "Sun May 30 2010 00:00:00 GMT+0300 (EEST)" }

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

items.save({
    name: "example",
    created_at: "Sun May 30 18.49:00 +0000 2010"
})
items.find({
    created_at: {
        $gte:"Mon May 30 18:47:00 +0000 2015",
        $lt: "Sun May 30 20:40:36 +0000 2010"
    }
})
=> { "_id" : ObjectId("4c079123b9ec877893f33638"), "name" : "example", "created_at" : "Sun May 30 18.49:00 +0000 2010" }

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

Чтобы уточнить. Важно знать, что:

  • Да, вы должны передать объект Javascript Date.
  • Да, это должно быть ISODate дружественным
  • Да, из моего опыта, чтобы заставить это работать, вам нужно манипулировать датой в ISO
  • Да, работа с датами, как правило, всегда утомительный процесс, и Монго не является исключением

Вот рабочий фрагмент кода, где мы делаем небольшую манипуляцию датами, чтобы гарантировать, что Mongo (здесь я использую модуль mongoose и хочу получить результаты для строк, чей атрибут date меньше (до) даты, указанной в параметре myDate), может обрабатывать это правильно:

var inputDate = new Date(myDate.toISOString());
MyModel.find({
    'date': { $lte: inputDate }
})

Python и pymongo

Поиск объектов между двумя датами в Python с помощью pymongo в коллекции posts (на основе учебника):

from_date = datetime.datetime(2010, 12, 31, 12, 30, 30, 125000)
to_date = datetime.datetime(2011, 12, 31, 12, 30, 30, 125000)

for post in posts.find({"date": {"$gte": from_date, "$lt": to_date}}):
    print(post)

куда {"$gte": from_date, "$lt": to_date} определяет диапазон с точки зрения datetime.datetime типы.

db.collection.find({"createdDate":{$gte:new ISODate("2017-04-14T23:59:59Z"),$lte:new ISODate("2017-04-15T23:59:59Z")}}).count();

замещать collection с именем коллекции, которую вы хотите выполнить запрос

MongoDB на самом деле хранит миллис даты как int(64), как предписано http://bsonspec.org/

Однако это может привести к путанице при получении дат, поскольку драйвер клиента будет создавать экземпляр объекта даты со своим собственным локальным часовым поясом. Драйвер JavaScript в консоли mongo, безусловно, сделает это.

Так что, если вы заботитесь о своих часовых поясах, убедитесь, что вы знаете, что это должно быть, когда получите его обратно. Это не должно иметь большого значения для запросов, так как все равно будет равняться тому же самому int(64), независимо от того, в каком часовом поясе находится ваш объект даты (я надеюсь). Но я бы определенно делал запросы с фактическими объектами даты (не строками) и позволял бы драйверу делать свое дело.

Использование с Moment.js и операторами сравнения запросов

  var today = moment().startOf('day');
  // "2018-12-05T00:00:00.00
  var tomorrow = moment(today).endOf('day');
  // ("2018-12-05T23:59:59.999

  Example.find(
  {
    // find in today
    created: { '$gte': today, '$lte': tomorrow }
    // Or greater than 5 days
    // created: { $lt: moment().add(-5, 'days') },
  }), function (err, docs) { ... });

Используйте этот код, чтобы найти запись между двумя датами, используя $gte а также $lt:

db.CollectionName.find({"whenCreated": {
    '$gte': ISODate("2018-03-06T13:10:40.294Z"),
    '$lt': ISODate("2018-05-06T13:10:40.294Z")
}});

Сохраните дату created_at в формате даты ISO, затем используйте $gte и $lte.

      db.connection.find({
    created_at: {
        $gte: ISODate("2010-05-30T18:47:00.000Z"),
        $lte: ISODate("2010-05-30T19:00:00.000Z")
    }
})
db.collection.find({$and:
  [
    {date_time:{$gt:ISODate("2020-06-01T00:00:00.000Z")}},
     {date_time:{$lt:ISODate("2020-06-30T00:00:00.000Z")}}
   ]
 })

##In case you are making the query directly from your application ##

db.collection.find({$and:
   [
     {date_time:{$gt:"2020-06-01T00:00:00.000Z"}},
     {date_time:{$lt:"2020-06-30T00:00:00.000Z"}}
  ]

 })

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

db.getCollection('user').find({
    createdOn: {
        $gt: ISODate("2020-01-01T00:00:00.000Z"),
        $lt: ISODate("2020-03-01T00:00:00.000Z")
    }
})

Используйте $gte и $lte для поиска данных даты в mongodb

var tomorrowDate = moment(new Date()).add(1, 'days').format("YYYY-MM-DD");
db.collection.find({"plannedDeliveryDate":{ $gte: new Date(tomorrowDate +"T00:00:00.000Z"),$lte: new Date(tomorrowDate + "T23:59:59.999Z")}})
mongoose.model('ModelName').aggregate([
    {
        $match: {
            userId: mongoose.Types.ObjectId(userId)
        }
    },
    {
        $project: {
            dataList: {
              $filter: {
                 input: "$dataList",
                 as: "item",
                 cond: { 
                    $and: [
                        {
                            $gte: [ "$$item.dateTime", new Date(`2017-01-01T00:00:00.000Z`) ]
                        },
                        {
                            $lte: [ "$$item.dateTime", new Date(`2019-12-01T00:00:00.000Z`) ]
                        },
                    ]
                 }
              }
           }
        }
     }
])

Для тех, кто использует Integromat и MongoDB : я изо всех сил пытался найти правильный способ запроса всех записей между двумя датами. В конце концов, все, что мне нужно было сделать, это удалить ISODateкак предлагается в некоторых решениях здесь. Таким образом, полный код будет таким:

      "created": {
    "$gte": "2016-01-01T00:00:00.000Z",
    "$lt": "2017-01-01T00:00:00.000Z"
}

Эта статья помогла мне достичь моей цели.

Почему бы не преобразовать строку в целое число вида ГГГГММДДЧЧММСС? Затем каждый прирост времени будет создавать большее целое число, и вы сможете фильтровать целые числа, не беспокоясь о преобразовании во время ISO.

Конвертируйте ваши даты в часовой пояс GMT, когда вы вводите их в Mongo. Таким образом, никогда не бывает проблем с часовыми поясами. Тогда просто сделайте математику в поле твиттера / часового пояса, когда вы извлекаете данные обратно для представления.

Scala: с синтаксисом joda DateTime и BSON (reactivemongo):

      val queryDateRangeForOneField = (start: DateTime, end: DateTime) =>
    BSONDocument(
      "created_at" -> BSONDocument(
        "$gte" -> BSONDateTime(start.millisOfDay().withMinimumValue().getMillis), 
        "$lte" -> BSONDateTime(end.millisOfDay().withMaximumValue().getMillis)),
     )

куда millisOfDay().withMinimumValue() для «2021-09-08T06: 42: 51.697Z» будет «2021-09-08T00: 00: 00.000Z», а где millisOfDay(). withMaximumValue() для «2021-09-08T06: 42: 51.697Z» будет «2021-09-08T23: 59: 99.999Z».

Я попытался в этой модели в соответствии с моими требованиями мне нужно сохранить дату, когда когда-либо объект создается позже, я хочу получить все записи (документы) между двумя датами в моем HTML-файле, я использовал следующий формат мм / дд / гггг

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>

    <script>
//jquery
    $(document).ready(function(){  
    $("#select_date").click(function() { 
    $.ajax({
    type: "post",
    url: "xxx", 
    datatype: "html",
    data: $("#period").serialize(),  
    success: function(data){
    alert(data);
    } ,//success

    }); //event triggered

    });//ajax
    });//jquery  
    </script>

    <title></title>
</head>

<body>
    <form id="period" name='period'>
        from <input id="selecteddate" name="selecteddate1" type="text"> to 
        <input id="select_date" type="button" value="selected">
    </form>
</body>
</html>

в моем файле py (python) я преобразовал его в "iso fomate" следующим образом

date_str1   = request.POST["SelectedDate1"] 
SelectedDate1   = datetime.datetime.strptime(date_str1, '%m/%d/%Y').isoformat()

и сохранен в моей коллекции dbmongo с "SelectedDate" в качестве поля в моей коллекции

чтобы получить данные или документы между двумя датами, я использовал следующий запрос

db.collection.find( "SelectedDate": {'$gte': SelectedDate1,'$lt': SelectedDate2}})
Другие вопросы по тегам