MongoDB $, где запросы и настраиваемые курсоры - WAS: лучшие практики по математике - PullRequest
5 голосов
/ 05 декабря 2011

Моя проблема: дайте мне список документов старше X количества времени.

Если у меня есть документ, созданный с:

db.dates.insert({date: new Date()});

А теперьЯ хочу найти его только тогда, когда «дата» устарела через 30 минут:

db.dates.find({ $where: "this.date.getTime() + 30 * 60000 <= new Date()"});

Это работает, но в документации Mongo довольно ясно говорится о существенном снижении производительностик $ где запросы.

Таким образом, вопрос, есть ли лучший способ?

========== ОБНОВЛЕНИЕ 1 ==========

Я должен был добавить, что надеюсь, что эта функция запроса "динамически" будет создавать запрос один раз и использовать его для получения настраиваемого курсора на закрытой коллекции ... и я больше не уверен, чтона самом деле это возможно.

Я буду тестировать и перепечатывать.

========== ОБНОВЛЕНИЕ 2 ==========

Итак, похоже, что мою «отложенную» очередь нужно будет обрабатывать в коде, либо с помощью опроса, либо с помощью какого-либо алгоритма «проверить, потом спать», потому что это, похоже, задержка Монговыполняется репликация d (из db.cpp):

if ( replSettings.slavedelay && ( unsigned( time( 0 ) ) < nextOpTime.getSecs() + replSettings.slavedelay ) ) {
    assert( justOne );
    oplogReader.putBack( op );
    _sleepAdviceTime = nextOpTime.getSecs() + replSettings.slavedelay + 1;
    dblock lk;
    if ( n > 0 ) {
        syncedTo = last;
        save();
    }
    log() << "repl:   applied " << n << " operations" << endl;
    log() << "repl:   syncedTo: " << syncedTo.toStringLong() << endl;
    log() << "waiting until: " << _sleepAdviceTime << " to continue" << endl;
    return okResultCode;
}

Ответы [ 4 ]

4 голосов
/ 05 декабря 2011

Оператор $lte (и другие запросы диапазона) будет работать и использовать индексы, но не может оценивать выражения. Вы должны выполнить запрос к постоянной времени запроса (которая будет «сейчас - 30 минут»):

var threshold = new Date(); 
threshold.setMinutes(-30);

// now, query against a constant:
db.dates.find({"date" : {$lte : threshold}});

Конечно, вы можете сделать то же самое с любым драйвером для любого языка программирования, например, C #

var c = db.Collection.Find(Query.LTE("date", DateTime.UtcNow.AddMinutes(-30));
0 голосов
/ 07 декабря 2011

Так что мой предыдущий ответ на мой вопрос не прошел все юнит-тесты.Он прошел все, кроме одного:

Вставка записи, которая в конечном итоге будет доступна, пока к коллекции был присоединен настраиваемый курсор.

Настройка теста следующая:

  1. В отдельном потоке прикрепите настраиваемый курсор к коллекции.
  2. В главном потоке вставьте в коллекцию документ, который должен быть доступен через X раз.
  3. Спите основнойнить за количество времени X.
  4. Проверьте, есть ли у документа с настраиваемым курсором документ.

Единственный способ, которым я смог заставить это работать, состоял в том, чтобы имитировать частьлогика отложенного оплога:

if (cursor.hasNext()) {
    DBObject obj = cursor.next();

    if (config.getQueueDelay() > 0) {
        ObjectId objId = (ObjectId) obj.get("_id");
        long advisedSleep = (objId.getTime() + config.getQueueDelay() * 60000)
        - System.currentTimeMillis();
        if (advisedSleep > 0 ) {
            LOG.debug(
                "object is not yet old enough, sleeping for: " 
                 + advisedSleep + "ms"
            );
            Thread.sleep(advisedSleep);
        }
    }
    return obj;
}

На мой взгляд, это нормальный алгоритм, поскольку, поскольку рассматриваемая коллекция опирается на автоматически созданные ObjectIds, мы можем быть на 100% уверены, что объекты находятся в правильном порядке, иесли мы не можем быть уверены в этом, то мы всегда можем добавить заказ к начальному запросу.

С другой стороны, коллекция должна иметь ObjectId (мой код имеетпредполагается, что он находится в поле _id объекта, но его можно легко изменить на настраиваемое значение).

0 голосов
/ 06 декабря 2011

Итак, я должен был проверить в начале!Мой оригинальный запрос работает, как и ожидалось, даже в случае настраиваемых курсоров.

Как оказалось, Mongo, похоже, переоценивает javascript $ where при каждой вставке записи в коллекцию.

Я полагаю, что это действительно имеет полный смысл, учитывая тот факт, что вы можете ссылаться на объект "this" - если javascript не повторяется каждый раз, тогда "this" будет фактически означать "first".

эффективность этого еще предстоит выяснить, особенно когда в коллекцию добавляется все больше и больше настраиваемых курсоров.

0 голосов
/ 05 декабря 2011

На аналогичный вопрос был получен ответ Запрос Mongodb о месяце, дне, году ... даты и времени

Идея состоит в том, чтобы запросить диапазоны конца и начала необходимого времени,Ваш запрос может быть легко переведен на то, что вам нужно.Просто используйте new Date() на одной стороне и this.date.getTime() + 30 * 60000 на другой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...