Удалить документы по сравнению даты между суммой даты и числовых полей и текущей отметкой времени

Документы в коллекции MongoDB имеют следующую схему (показаны только соответствующие поля):

{
    "TTLinSeconds" : 1800,
    "lastUpdatedTimestamp" : ISODate("...")
}

Мне нужно удалить все документы, где current timestamp больше, чем lastUpdatedTimestamp плюс значение, хранящееся в TTLinSeconds поле. Заранее спасибо за ваши предложения.

3 ответа

Решение

Вы можете использовать структуру агрегирования с $redact а также $out трубопроводы для удаления документов, которые удовлетворяют данному условию.

$redact Трубопровод включает в себя функциональность $project а также $match реализовать редактирование на уровне поля, где он вернет все документы, соответствующие условию, используя $$KEEP и удаляет те, которые не соответствуют, используя $$PRUNE переменная.

$out pipe записывает итоговые документы конвейера агрегации в одну и ту же коллекцию, таким образом, по существу, выполняет операцию обновления.


Выполнение следующей агрегатной операции удалит документы:

db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$lte": [ 
                        new Date(), 
                        { 
                            "$add": [
                                "$lastUpdatedTimestamp", 
                                { "$multiply": ["$TTLinSeconds", 1000] }
                            ] 
                        } 
                    ] 
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    { "$out": "collection" }
])

Как предостережение, используя $where Оператор не будет работать очень хорошо, так как обработка запроса занимает некоторое время из-за того, что MongoDB делает негласно: когда вы выполняете обычное (не $where) запрос, ваш клиент превращает этот запрос в BSON и отправляет его в базу данных. MongoDB также хранит данные в BSON, поэтому он может сравнивать ваш запрос непосредственно с данными. Это очень быстро и эффективно.

С другой стороны, когда у вас есть $where Предложение, которое должно быть выполнено как часть вашего запроса, MongoDB должен будет создать объект JavaScript для каждого документа в коллекции, проанализировав BSON документов и добавив все их поля в объекты JavaScript. Затем он выполняет JavaScript-код, который вы отправили для документов, а затем снова разрушает его. Это чрезвычайно трудоемкая и ресурсоемкая операция, поскольку она вызывает механизм JavaScript для оценки кода Javascript для каждого документа и проверки условия для каждого. Желательно объединить с индексированными запросами, если вы можете, чтобы запрос мог быть быстрее.

Некоторые соображения, которые вы должны учитывать при использовании $where:

Не используйте глобальные переменные.

$where оценивает JavaScript и не может использовать преимущества индексов. Следовательно, производительность запроса улучшается, когда вы выражаете запрос с помощью стандартных операторов MongoDB (например, $gt, $in). В общем, вы должны использовать $where только когда вы не можете выразить свой запрос, используя другой оператор. Если вы должны использовать $where попробуйте включить хотя бы один стандартный оператор запроса для фильтрации набора результатов. С помощью $where один требует сканирования таблицы. Используя обычные $where операторы запроса обеспечивают следующие преимущества производительности:

MongoDB будет оценивать не $where компоненты запроса перед $where заявления. Если не $where операторы не соответствуют ни одному документу, MongoDB не будет выполнять оценку запросов с использованием $where, Затем на- $where операторы запроса могут использовать индекс.

$where это хороший взлом, когда это необходимо, но его следует избегать, когда это возможно. Если $where запрос, вы можете снизить производительность, сведя к минимуму количество документов, которые попадают в $where или создать дополнительное вычисленное денормализованное поле скажем expiryDate это сумма lastUpdatedTimestamp и TTLinSeconds поля, которые вы можете запросить как:

db.collection.remove({ "expiryDate": { "$lt": new Date() }});

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

Это может сработать (чтобы удалить поле между 2017-01-25T00:30:00Z и 2017-01-26T23:59:00Z):

  db.collectionName.remove({
       $and : [
        {"lastUpdatedTimestamp": { 
           $gte:   ISODate("2017-01-25T00:30:00Z"), 
           $lt :   ISODate("2017-01-26T23:59:00Z")
       },
       {"TTLinSeconds" : value}
      ]
    }  

Предложение:

Я бы порекомендовал вам использовать общее соглашение об именах для ваших переменных.

Ссылка:

https://docs.mongodb.com/manual/reference/operator/update/currentDate/

Вы можете сделать это используя $where как:

db.collectionName.remove({$where:"new Date().getTime() > this.lastUpdatedTimestamp.getTime() + (this.TTLinSeconds * 1000)"})
Другие вопросы по тегам