A consulta de data com ISODate no mongodb parece não funcionar

189

Parece que não consigo obter nem a consulta de data mais básica para trabalhar no MongoDB. Com um documento que se parece com isso:

{
    "_id" : "foobar/201310",
    "ap" : "foobar",
    "dt" : ISODate("2013-10-01T00:00:00.000Z"),
    "tl" : 375439
}

E uma consulta que se parece com isso:

{ 
    "dt" : { 
        "$gte" : { 
            "$date" : "2013-10-01T00:00:00.000Z"
        }
    }
}

Eu recebo 0 resultados da execução:

db.mycollection.find({
  "dt" : { "$gte" : { "$date" : "2013-10-01T00:00:00.000Z"}}
})

Alguma idéia de por que isso não funciona?

Para referência, essa consulta está sendo produzida pelo MongoTemplate do Spring, portanto, não tenho controle direto sobre a consulta que é finalmente enviada ao MongoDB.

(PS)

> db.version()
2.4.7

Obrigado!

Jason Polites
fonte

Respostas:

312

Embora faça $dateparte do MongoDB Extended JSON e é isso que você obtém como padrão commongoexport acho que você realmente não pode usá-lo como parte da consulta.

Se tentar a pesquisa exata, $datecomo abaixo:

db.foo.find({dt: {"$date": "2012-01-01T15:00:00.000Z"}})

você receberá um erro:

error: { "$err" : "invalid operator: $date", "code" : 10068 }

Tente o seguinte:

db.mycollection.find({
    "dt" : {"$gte": new Date("2013-10-01T00:00:00.000Z")}
})

ou (comentários a seguir por @ user3805045 ):

db.mycollection.find({
    "dt" : {"$gte": ISODate("2013-10-01T00:00:00.000Z")}
})

ISODatetambém pode ser necessário comparar datas sem tempo (observado por @MattMolnar ).

De acordo com os tipos de dados no mongo Shell, ambos devem ser equivalentes:

O shell mongo fornece vários métodos para retornar a data, como uma string ou como um objeto Date:

  • Date () método que retorna a data atual como uma string.
  • novo construtor Date () que retorna um objeto Date usando o wrapper ISODate ().
  • Construtor ISODate () que retorna um objeto Date usando o wrapper ISODate ().

e use ISODate ainda deve retornar um objeto Date .

{"$date": "ISO-8601 string"}pode ser usado quando uma representação JSON estrita é necessária. Um exemplo possível é o conector Hadoop.

zero323
fonte
3
Sim. Acho que fiquei impressionado com o que é retornado quando você imprime o Queryobjeto no Spring. A forma serializada da consulta não é necessariamente uma consulta válida que você pode simplesmente copiar / colar em um shell mongo, o que por si só é meio frustrante. O culpado é aqui: grepcode.com/file/repo1.maven.org/maven2/org.mongodb/...
Jason Polites
2
Ao comparar uma data parcial (sem horário), tive que mudar de new Date('2016-03-09')para ISODate('2016-03-09'). O primeiro retornaria datas no passado para uma $gteconsulta.
precisa
@MattMolnar Observou e atualizou a resposta com uma atribuição. Obrigado.
precisa saber é
92

Nos comentários da página do livro de receitas do MongoDB :

"dt" : 
{
    "$gte" : ISODate("2014-07-02T00:00:00Z"), 
    "$lt" : ISODate("2014-07-03T00:00:00Z") 
}

Isso funcionou para mim. No contexto completo, o comando a seguir obtém todos os registros em que o dtcampo date possui uma data no Zulu 2013-10-01 (AAAA-MM-DD):

db.mycollection.find({ "dt" : { "$gte" : ISODate("2013-10-01T00:00:00Z"), "$lt" : ISODate("2013-10-02T00:00:00Z") }})
Steve HHH
fonte
1
Eu recebi um erro "ISODate indefinido". Não consegui resolver esse problema.
Batuhan Akkaya
@BatuhanAkkaya Em python com pymongo, datetime.datetimeé equivalente a ISODate.
jtbr
12

Tente o seguinte:

{ "dt" : { "$gte" : ISODate("2013-10-01") } }
Jabba
fonte
5

Estou usando o robomongo como o GUI do cliente mongodb e o abaixo funcionou para mim

db.collectionName.find({"columnWithDateTime" : {
$lt:new ISODate("2016-02-28T00:00:00.000Z")}})

No lado do aplicativo, estou usando o driver mongodb baseado em nodejs (v1.4.3), o aplicativo usa o datepicker na interface do usuário que fornece uma data como AAAA-mm-dd, que é anexada ao horário padrão como 00:00:00 e depois para o new Date()construtor e, em seguida, fornecido ao objeto de critério mongodb, acho que o driver converte a data em data ISO e a consulta funciona e fornece a saída desejada, porém a mesmanew Date() construtor não funciona ou mostra a mesma saída no robo mongo, pela mesma critérios, o que é estranho, já que eu usei o robomongo para cruzar meus objetos de critérios.

Enquanto o cli mongoshell padrão funciona bem com ambos ISODateenew Date()

siddharthrc
fonte
1
Obrigado pela dica, Robomongo é muito melhor do Mongo Compass
Alex
5

No modo estrito json, você terá que manter a ordem:

{
    "dt": {
        "$gte": {
            "$date": "2013-10-01T00:00:00.000Z"
        }
    }
}

A única coisa que funcionou para definir minhas consultas de pesquisa no mlab.com.

3vangelos
fonte
Erro ao executar a consulta. Razão: (invalid_operator) Operador inválido: $ date
sabre tabatabaee yazdi
2

No shell do MongoDB:

db.getCollection('sensorevents').find({from:{$gt: new ISODate('2015-08-30 16:50:24.481Z')}})

No meu código nodeJS (usando Mongoose)

    SensorEvent.Model.find( {
        from: { $gt: new Date( SensorEventListener.lastSeenSensorFrom ) }
    } )

Estou consultando minha coleção de eventos do sensor para retornar valores em que o campo 'de' é maior que a data especificada

lewma
fonte
4
Bem-vindo ao Stack Overflow! Por favor, basta postar a resposta à pergunta, e não coisas extras como "Este é o meu primeiro post". Pense no Stack Overflow como Wikipedia, não como um quadro de mensagens.
precisa saber é o seguinte
1

este é o meu documento

"_id" : ObjectId("590173023c488e9a48e903d6"),
    "updatedAt" : ISODate("2017-04-27T04:26:42.709Z"),
    "createdAt" : ISODate("2017-04-27T04:26:42.709Z"),
    "flightId" : "590170f97cb84116075e2680",

 "_id" : ObjectId("590173023c488e9a48e903d6"),
        "updatedAt" : ISODate("2017-04-28T03:26:42.609Z"),
        "createdAt" : ISODate("2017-04-28T03:26:42.609Z"),
        "flightId" : "590170f97cb84116075e2680",

Agora eu quero encontrar todos os documentos data 27.so eu usei isso ....

 > db.users.find({createdAt:{"$gte":ISODate("2017-04-27T00:00:00Z"),"$lt":ISODate("2017-04-28T00:00:00Z") }}).count()

result:1

isso funcionou para mim.

codificador
fonte
0

Isso funcionou para mim enquanto procurava um valor menor ou igual ao agora:

db.collectionName.find({ "dt": { "$lte" : new Date() + "" } });
JulienRioux
fonte
0

Envolva-o com new Date():

{ "dt" : { "$lt" : new Date("2012-01-01T15:00:00.000Z") } }
Ehsan sarshar
fonte
0

Pergunta antiga, mas ainda o primeiro hit do Google, por isso eu o publico aqui, para encontrá-lo mais facilmente ...

Usando o Mongo 4.2 e um agregado ():

db.collection.aggregate(
    [
     { $match: { "end_time": { "$gt": ISODate("2020-01-01T00:00:00.000Z")  } } },
     { $project: {
          "end_day": { $dateFromParts: { 'year' : {$year:"$end_time"}, 'month' : {$month:"$end_time"}, 'day': {$dayOfMonth:"$end_time"}, 'hour' : 0  } }
     }}, 
     {$group:{
        _id:   "$end_day",
        "count":{$sum:1},
    }}
   ]
)

Este fornece a variável groupby como uma data, às vezes é melhor manipular os componentes em si.

A. Rabus
fonte