Объедините два $ или заявления - PullRequest
12 голосов
/ 07 января 2012

Я пытаюсь выполнить запрос, который состоит из двух $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 можно выполнить таким образом.

Итак, вопрос в том, как мне построить свой запрос таким образом, чтобы я мог объединить два $ или в один запрос?

(Становится очень поздно, поэтому я надеюсь, что этот вопрос имеет смысл.)

Ответы [ 2 ]

9 голосов
/ 07 января 2012
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 ||

query

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 ]

это тоже должно работать (предположим, что 'not Существует' и 'NULL' то же самое)

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")} }
      ]}
  ]
}
)
0 голосов
/ 07 января 2012

На самом деле проблема не в логической композиции. Ваш вложенный запрос $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 в монго.

> ISODate('2012-01-07T04:45:52.057Z')
ISODate("2012-01-07T04:45:52.057Z")

ОБНОВЛЕНИЕ : добавить тесты:

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...