Удалить документы по сравнению даты между суммой даты и числовых полей и текущей отметкой времени
Документы в коллекции 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)"})