Pour MongoDB 3.6 et versions ultérieures :
Le $expr
L'opérateur permet l'utilisation d'expressions d'agrégation dans le langage de requête, vous pouvez donc tirer parti de l'utilisation de $dateToString
opérateur pour transformer le champ date :
db.test.find({
"$expr": {
"$ne": [
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$created" } },
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$last_active" } }
]
}
})
ou en utilisant le cadre d'agrégation avec $match
pipeline
db.test.aggregate([
{ "$match": {
"$expr": {
"$ne": [
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$created" } },
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$last_active" } }
]
}
} }
])
Pour MongoDB 3.0+ :
Vous pouvez également utiliser le cadre d'agrégation avec le $redact
opérateur de pipeline qui vous permet de traiter la condition logique avec le $cond
et utilise les opérations spéciales $$KEEP
pour "conserver" le document où la condition logique est vraie ou $$PRUNE
pour "supprimer" le document où la condition était fausse.
Envisagez d'exécuter l'opération d'agrégation suivante qui illustre le concept ci-dessus :
db.test.aggregate([
{
"$redact": {
"$cond": [
{
"$ne": [
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$created" } },
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$last_active" } }
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
Cette opération est similaire à avoir un $project
pipeline qui sélectionne les champs de la collection et crée un nouveau champ contenant le résultat de la requête de condition logique, puis un $match
, sauf que $redact
utilise une seule étape de pipeline qui est plus efficace :
db.test.aggregate([
{
"$project": {
"created": 1,
"last_active": 1,
"sameDay": {
"$cond": [
{
"$eq": [
{"$substr" : ["$last_active",0, 10]},
{"$substr" : ["$created",0, 10]}
]
}, true, false
]
}
}
},
{ "$match": { "sameDay": false } }
])
0r
db.test.aggregate([
{
"$project": {
"created": 1,
"last_active": 1,
"sameDay": {
"$cond": [
{
"$eq": [
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$created" } },
{ "$dateToString": { "format": "%Y-%m-%d", "date": "$last_active" } }
]
}, true, false
]
}
}
},
{ "$match": { "sameDay": false } }
])
Une autre approche serait d'utiliser le $where
opérateur dans votre find()
mais notez que la requête sera assez lente car l'utilisation de $where
nécessite à elle seule une analyse de table et la base de données exécute l'expression ou la fonction JavaScript pour chaque document de la collection, donc combinez-les avec des requêtes indexées si vous le pouvez, car les performances des requêtes s'améliorent également lorsque vous les exprimez à l'aide des opérateurs MongoDB standard (par exemple, $gt
, $in
):
db.test.find({
"$where": function() {
return this.created.getDate() !== this.last_active.getDate()
}
});
ou plus compact :
db.test.find({ "$where": "this.created.getDate() !== this.last_active.getDate()" });
Avec l'entrée :
/* 0 */
{
"_id" : 1,
"created" : ISODate("2014-12-19T06:01:17.171Z"),
"last_active" : ISODate("2014-12-21T15:38:13.842Z")
}
/* 1 */
{
"_id" : 2,
"created" : ISODate("2015-07-06T12:17:32.084Z"),
"last_active" : ISODate("2015-07-06T18:07:08.145Z")
}
/* 2 */
{
"_id" : 3,
"created" : ISODate("2015-07-06T06:01:17.171Z"),
"last_active" : ISODate("2015-07-07T10:04:30.921Z")
}
/* 3 */
{
"_id" : 4,
"created" : ISODate("2015-07-06T06:01:17.171Z"),
"last_active" : ISODate("2015-07-06T09:47:44.186Z")
}
/* 4 */
{
"_id" : 5,
"created" : ISODate("2013-12-19T06:01:17.171Z"),
"last_active" : ISODate("2014-01-20T13:21:37.427Z")
}
L'agrégation renvoie :
/* 0 */
{
"result" : [
{
"_id" : 1,
"created" : ISODate("2014-12-19T06:01:17.171Z"),
"last_active" : ISODate("2014-12-21T15:38:13.842Z"),
"sameDay" : false
},
{
"_id" : 3,
"created" : ISODate("2015-07-06T06:01:17.171Z"),
"last_active" : ISODate("2015-07-07T10:04:30.921Z"),
"sameDay" : false
},
{
"_id" : 5,
"created" : ISODate("2013-12-19T06:01:17.171Z"),
"last_active" : ISODate("2014-01-20T13:21:37.427Z"),
"sameDay" : false
}
],
"ok" : 1
}