#mongodb #mongodb-query #aggregation-framework
#mongodb #mongodb-запрос #агрегация-фреймворк
Вопрос:
У меня есть данные Twitter, которые выглядят следующим образом:
db.users.findOne()
{
"_id" : ObjectId("578ffa8e7eb9513f4f55a935"),
"user_name" : "koteras",
"retweet_count" : 0,
"tweet_followers_count" : 461,
"source" : "<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>",
"coordinates" : null,
"tweet_mentioned_count" : 1,
"tweet_ID" : "755891629932675072",
"tweet_text" : "RT @ochocinco: I beat them all for 10 straight hours #FIFA16KING",
"user" : {
"CreatedAt" : ISODate("2011-12-27T09:04:01Z"),
"FavouritesCount" : 5223,
"FollowersCount" : 461,
"FriendsCount" : 619,
"UserId" : 447818090,
"Location" : "501"
}
Например, я хочу найти количество пользователей, у которых «FollowersCount» больше, чем «Favoritescount». Как я могу это сделать?
Ответ №1:
Оператор $where специально разработан для этого.
db.users.find( { $where: function() { return (this.user.FollowersCount > this.user.FavouritesCount) } } );
Но имейте в виду, что это привело бы к запуску однопоточного JS-кода и было бы медленнее.
Другой вариант — использовать конвейер агрегации, проецирующий разницу, а затем имеющий $match
для этой разницы
db.users.aggregate([
{$project: {
diff: {$subtract: ["$user.FollowersCount", "$user.FavouritesCount"]},
// project remaining fields here
}
},
{$match: {diff: {$gt: 0}}}
])
По своему опыту я обнаружил, что второй способ намного быстрее первого.
Комментарии:
1. И в обоих случаях применитесь
itcount()
к возвращаемому курсору, чтобы получить количество совпадающих документов2. Спасибо, чувак! Что насчет функции «и»? Если я хочу найти твиты, которые содержат определенный текст и из определенного местоположения.
3. Я пробовал это, и это не работает db.users.find({$и [{«пользователь. Местоположение»: «501»},{ tweet_text: /UEFA/}]})
4. В
$and
этом нет необходимости.workdb.users.find({"user.Location": "501", tweet_text: /UEFA/})
также должно работать
Ответ №2:
Чтобы получить количество пользователей, у которых «FollowersCount» больше, чем «Favoritescount», вы могли бы использовать платформу агрегации, в которой есть некоторые операторы, которые вы можете применить.
Рассмотрим первый вариант использования, который рассматривает манипулирование операторами сравнения в $project
конвейере и последующем $match
конвейере для фильтрации документов на основе $cmp
значения. Затем вы можете получить окончательное количество пользователей, применив $group
конвейер, который объединяет отфильтрованные документы:
db.users.aggregate([
{
"$project": {
"hasMoreFollowersThanFavs": {
"$cmp": [ "$user.FollowersCount", "$user.FavouritesCount" ]
}
}
},
{ "$match": { "hasMoreFollowersThanFavs": 1 } },
{
"$group": {
"_id": null,
"count": { "$sum": 1 }
}
}
])
Другим вариантом является использование единого конвейера с $redact
оператором, который включает в себя функциональность $project
и $match
, как указано выше, и возвращает все документы, которые соответствуют указанному условию, используя $$KEEP
системную переменную, и отбрасывает те, которые не соответствуют, используя $$PRUNE
системную переменную:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$eq": [
{ "$cmp": [ "$user.FollowersCount", "$user.FavouritesCount" ] },
1
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{
"$group": {
"_id": null,
"count": { "$sum": 1 }
}
}
])