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

298

Я занимаюсь хранением твитов внутри 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
}

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

  • 0
    Вы не говорите, по какому полю вы хотите запросить?
  • 0
    К сожалению, я хочу сделать запрос к create_at и найти все между двумя датами.
Показать ещё 2 комментария
Теги:
datetime
mongodb-query
twitter

12 ответов

481
Лучший ответ

Запрос для диапазона дат (определенный месяц или день) в Cookbook в 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" }

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

  • 2
    Выглядит интересно, но должна ли сохраненная дата быть в определенном формате. Я только что сохранил то, что было предоставлено Твиттером, нужно ли это изменить в другой формат?
  • 5
    Вы, вероятно, сохранили метки времени в виде строк, поэтому я предполагаю, что MongoDB не поймет, что это на самом деле даты. Таким образом, выполнение запроса диапазона к ним приведет к алфавитному запросу диапазона (например, «Jan Mon 01.01.2010» перед «Jan Sun 01.01.1000»). Вероятно, имеет смысл отформатировать все данные даты в формате MongoDB, который, как мне кажется, является просто датой JavaScript.
Показать ещё 5 комментариев
19

Прояснить. Важно знать, что:

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

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

var inputDate = new Date(myDate.toISOString());
MyModel.find({
    'date': { $lte: inputDate }
})
  • 1
    Плюс один для ясности. Если вы используете момент в бэкэнде, он все еще сохраняет функцию toISOString (). Я использую момент, чтобы сложить и вычесть время для моих запросов.
16

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

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

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

6

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.

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

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

  • 0
    Что это добавляет к принятому ответу (предоставлен 7 годами ранее)?
  • 1
    @ DanDascalescu - может быть, это ничего не добавило, но что вас здесь беспокоит?
Показать ещё 1 комментарий
3

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

db.CollectionName.find({"whenCreated": {
    '$gte': ISODate("2018-03-06T13:10:40.294Z"),
    '$lt': ISODate("2018-05-06T13:10:40.294Z")
}});
  • 0
    Что это добавляет к принятому ответу, предоставленному 8 годами ранее?
2

Почему бы не преобразовать строку в целое число формы YYYYMMDDHHMMSS? Каждое добавление времени создавало бы большее целое число, и вы могли бы фильтровать целые числа, а не беспокоиться о преобразовании в время ISO.

  • 0
    Потому что время не просто происходит в моем местном часовом поясе.
  • 2
    Это становится кошмаром, когда вы начинаете преобразовывать время в и из этого формата везде. Если вы собираетесь сделать что-то подобное по крайней мере, используйте возвращаемое значение из .getTime () из объекта даты JS.
Показать ещё 1 комментарий
2

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

0

Использование с 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) { ... });
0

используйте $ 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")}})
  • 1
    Небольшая опечатка в вашем ответе $ gte not $ get :)
  • 1
    Извините, я ответил на очень усталое состояние, поэтому я ошибся Спасибо за вашу помощь, чтобы обновить мой ответ. ты хорошо поработал :) @Bob
0

Имя коллекции: заказы

{
    "_id" : ObjectId("590070186bcc993d9c316ac1"),
    "updatedAt" : ISODate("2017-04-26T10:07:04.344Z"),
    "createdAt" : ISODate("2017-04-26T10:02:00.489Z"),
    "fullName" : "test last",
    "imgLength" : 5,
    "firstName" : "test",
    "lastName" : "last",
    "address" : "test",
    "state" : "test",
    "city" : "test",
    "zipCode" : 123456,
    "user" : ObjectId("58f760e771fd1737d1f9b4e5"),
    "orderId" : "PHA454494125243881",
    "status" : "Pending",
    "imgUrls" : [ ],
    "__v" : 0
}
{
    "_id" : ObjectId("590071622e6d953e411dec3f"),
    "updatedAt" : ISODate("2017-04-20T10:37:46.569Z"),
    "createdAt" : ISODate("2017-04-20T10:07:30.572Z"),
    "fullName" : "test last",
    "imgLength" : 5,
    "firstName" : "test",
    "lastName" : "last",
    "address" : "test",
    "state" : "test",
    "city" : "test",
    "zipCode" : 123456,
    "user" : ObjectId("58f760e771fd1737d1f9b4e5"),
    "orderId" : "PHA300991061399836",
    "status" : "Pending",
    "imgUrls" : [ ],
    "__v" : 0
}
{
    "_id" : ObjectId("590071902e6d953e411dec40"),
    "updatedAt" : ISODate("2017-04-15T10:08:16.111Z"),
    "createdAt" : ISODate("2017-04-15T10:08:16.111Z"),
    "fullName" : "test last",
    "imgLength" : 5,
    "firstName" : "test",
    "lastName" : "last",
    "address" : "test",
    "state" : "test",
    "city" : "test",
    "zipCode" : 123456,
    "user" : ObjectId("58f760e771fd1737d1f9b4e5"),
    "orderId" : "PHA876174070036339",
    "status" : "Pending",
    "imgUrls" : [ ],
    "__v" : 0
}

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

db.orders.find({
             createdAt:{
                     $gt:ISODate("2017-04-10T10:08:16.111Z"),
                     $lt:ISODate("2017-05-25T10:08:16.111Z")}
              }).pretty();

ваш результат будет следующим:

[

    {
        "_id" : ObjectId("590071622e6d953e411dec3f"),
        "updatedAt" : ISODate("2017-04-20T10:37:46.569Z"),
        "createdAt" : ISODate("2017-04-20T10:07:30.572Z"),
        "fullName" : "test last",
        "imgLength" : 5,
        "firstName" : "test",
        "lastName" : "last",
        "address" : "test",
        "state" : "test",
        "city" : "test",
        "zipCode" : 123456,
        "user" : ObjectId("58f760e771fd1737d1f9b4e5"),
        "orderId" : "PHA300991061399836",
        "status" : "Pending",
        "imgUrls" : [ ],
        "__v" : 0
    }
    {
        "_id" : ObjectId("590071902e6d953e411dec40"),
        "updatedAt" : ISODate("2017-04-15T10:08:16.111Z"),
        "createdAt" : ISODate("2017-04-15T10:08:16.111Z"),
        "fullName" : "test last",
        "imgLength" : 5,
        "firstName" : "test",
        "lastName" : "last",
        "address" : "test",
        "state" : "test",
        "city" : "test",
        "zipCode" : 123456,
        "user" : ObjectId("58f760e771fd1737d1f9b4e5"),
        "orderId" : "PHA876174070036339",
        "status" : "Pending",
        "imgUrls" : [ ],
        "__v" : 0
    }
]
0

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

<!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}})

Ещё вопросы

Сообщество Overcoder
Наверх
Меню