Объедините два $или утверждения
Я пытаюсь выполнить запрос, состоящий из двух $or
:
|--------------------
| Date1 | Date2 |
|--------------------
| NULL | NULL | *
| NULL | TODAY | *
| NULL | TOMRW |
| TODAY | TODAY | *
| TODAY | NULL | *
| TOMRW | NULL |
|--------------------
(Я отметил строки, которые соответствуют звездочке)
(Date1 == null || Date1 <= today) && (Date2 == null || Date2 <= today)
Я не уверен, как выразить этот запрос в MongoDB.
Его можно разбить на два отдельных запроса, которые делают именно то, что они должны:
{
"$or": [{
"Date1": {
"$exists": false
}
},
{
"Date1": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")
}
}]
}
и
{
"$or": [{
"Date2": {
"$exists": false
}
},
{
"Date2": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")
}
}]
}
Оба из них выбирают правильный набор документов - я просто не знаю, как выполнять их как один запрос.
Моя первоначальная мысль заключалась в том, чтобы сделать такой запрос:
{
$and: [orQuery1, orQuery2]
}
Использование запроса $and
возвращает 0 результатов. Было объяснено, почему здесь в этой теме: $и запрос не возвращает результат
Также в этом потоке было сделано предложение сделать такой запрос:
{
Key: {valToMatch1: 1, valToMatch2: 2}
}
Но я не думаю, что $or
может быть выполнен таким образом.
Итак, возникает вопрос: как мне построить свой запрос, чтобы я мог объединить два $или в один запрос?
(Его очень поздно, поэтому я надеюсь, что этот вопрос имеет смысл.)
Ответы
Ответ 1
use test
db.test.insert({a:1})
db.test.insert({a:2, Date2:new Date("01/07/2012")})
db.test.insert({a:3, Date2:new Date("01/08/2012")})
db.test.insert({a:4, Date1:new Date("01/07/2012"), Date2:new Date("01/07/2012")})
db.test.insert({a:5, Date1:new Date("01/07/2012")})
db.test.insert({a:6, Date1:new Date("01/08/2012")})
первый подзапрос db.test.distinct('a', {...});
[1, 2, 3]
второй подзапрос db.test.distinct('a', {...});
[1, 5, 6]
(Date1 == null || Date1 <= today) && (Date2 == null || Date2 <= today)
размотать
Date1 == null && Date2 == null ||
Date1 == null && Date2 <= today ||
Date1 <= today && Date2 == null ||
Date1 <= today && Date2 <= today ||
запроса
db.test.find(
{
$or :
[
{$and: [
{"Date1": {"$exists": false}},
{"Date2": {"$exists": false}}
]},
{$and: [
{"Date1": {"$exists": false}},
{"Date2": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")}
}
]},
{$and: [
{"Date2": {"$exists": false}},
{"Date1": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")}
}
]},
{$and: [
{"Date2": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")}
},
{"Date1": {
"$exists": true,
"$lte": new Date("2012-01-07T04:45:52.057Z")}
}
]}
]
})
>[ 1 ]
это тоже должно работать (предположим, что "не существует" и "нуль" одинаково)
db.test.find(
{
$and :
[
{$or: [
{"Date1": null},
{"Date1": { "$lte": new Date("2012-01-07T04:45:52.057Z")} }
]},
{$or: [
{"Date2": null},
{"Date2": { "$lte": new Date("2012-01-07T04:45:52.057Z")} }
]}
]
}
)
Ответ 2
Собственно, проблема заключается не в логической композиции. Ваш вложенный запрос $and
$or
отлично подходит.
Это различие между MongoDB и JavaScript на создании даты, которая препятствует вам.
в Монго:
> new Date("2012-01-07T04:45:52.057Z")
ISODate("0NaN-NaN-NaNTNaN:NaN:NaNZ")
в JavaScript:
> new Date("2012-01-07T04:45:52.057Z")
Sat, 07 Jan 2012 04:45:52 GMT
Чтобы исправить это, вы должны использовать ISODate
в mongo.
> ISODate('2012-01-07T04:45:52.057Z')
ISODate("2012-01-07T04:45:52.057Z")
UPDATE: добавить тесты:
чтобы доказать правильность вашей логической комбинации, я написал следующие скрипты:
populate.js
: заполните данные выборки:
var past = new Date('01/01/2011'),
future = new Date('01/01/2013');
var dates = [
{
num: 1
},
{
num: 2,
Date2: past
},
{
num: 3,
Date2: future
},
{
num: 4,
Date1: past,
Date2: past
},
{
num: 5,
Date1: past
},
{
num: 6,
Date1: future
}
];
dates.forEach(function(date) {
db.dates.insert(date);
});
query.js
: проверьте три запроса:
function queryNum(query) {
print(db.dates.find(query).map(function(v) {
return v.num;
}));
}
var q1 = {
"$or": [{
"Date1": {
"$exists": false
}
},
{
"Date1": {
"$exists": true,
"$lte": new Date('01/01/2012')
}
}]
};
var q2 = {
"$or": [{
"Date2": {
"$exists": false
}
},
{
"Date2": {
"$exists": true,
"$lte": new Date('01/01/2012')
}
}]
};
var q3 = {
$and: [q1, q2]
};
queryNum(q1);
queryNum(q2);
queryNum(q3);
Он правильно печатает:
1,2,3,4,5
2,2,4,5,6
1,2,4,5