I am running a query from my Meteor server, but for some reason only the first projection is catching.
Users.find({"services.facebook" : {$exists : true}}, {"_id": {$nin: doNotCount}}).fetch()
only returns facebook users (disregarding {"_id": {$nin: doNotCount}})
Users.find(, {"_id": {$nin: doNotCount}}, {"services.facebook" : {$exists : true}}).fetch()
only returns users not in a given array (disregarding {"services.facebook" : {$exists : true}})
from the documentation, it looks like this is possible:
https://docs.mongodb.org/manual/reference/operator/projection/positional/
but im not having any luck
The query is the first parameter only, the second parameter deals with sorting, limits, restricting the fields to be returned etc...
Change to:
Users.find({ "services.facebook" : {$exists : true}, "_id": {$nin: doNotCount }}).fetch()
Related
I'am trying to make an exercise with MongoDB database where I need to find movies in a movies collection , where the same person appears in cast, directors, and writers.
I tried this code :
//first match the writers, directors and cast arrays which are not empty.
db.movies.aggregate( [ {$match : {$and : [ {writers: {$elemMatch: {$exists: true}}} , {directors: {$elemMatch: {$exists: true}}} , {cast: {$elemMatch : {$exists: true}}} ]}}
//then make an intersection between the matched results
, {$project: {"labers of love" :{$setIntersection: ["$writers", "$cast", "$directors"]}, _id: 0 } } ] ).pretty()
However , when I run this command I still get empty arrays which should not be the case. I'am not sure if this pipeline is working properly. When I run only the $match command I dont seem to get any empty array.
I have a database in MongoDB. There are three main fields: _id, Reviews, HotelInfo. Reviews and HotelInfo are arrays. Reviews has a field called Author. I would like to print out every author name (once) and the amount of times they appear within the dataset.
I tried:
db.reviews.aggregate( {$group : { _id : '$Reviews.Author', count : {$sum : 1}}} ).pretty()
A part of the results were:
"_id" : [
"VijGuy",
"Stephtastic",
"dakota431",
"luce_sociator",
"ArkansasMomOf3",
"ccslilqt6969",
"RJeanM",
"MissDusty",
"sammymd",
"A TripAdvisor Member",
"A TripAdvisor Member"
],
"count" : 1
How it should be:
{ "_id" : "VijGuy", "count" : 1 }, { "_id" : "Stephtastic", "count" : 1 }
I posted the JSON format below.
Any idea on how to do this would be appreciated
JSON Format
Lets assume that this is our collection.
[{
_id: 1,
Reviews: [{Author: 'elad' , txt: 'good'}, {Author: 'chen', txt: 'bad'}]
},
{
_id: 2,
Reviews: [{Author: 'elad', txt : 'nice'}]
}]
to get the data as you want we need to first use the unwind stage and then the group stage.
[{ $unwind: '$Reviews' }, {$group : { _id : '$Reviews.Author', count : {$sum : 1}}}]
You need to first unwind the collection by the Reviews field.
after the unwind stage our data in the pipeline will look like this.
{_id:1, Reviews: {Author: 'elad' , txt: 'good'}},
{_id:1, Reviews: {Author: 'chen' , txt: 'bad'}},
{_id:2, Revies: {Author: 'elad', txt : 'nice'}
The unwind created a document for each element in Reviews array with the element itself and his host document. Now its easy to group in useful ways as you want. Now we can use the same group that you wrote and we will get the results.
after the group our data will look like this:
[{_id: 'elad',sum:2},{_id: 'chen', sum: 1}]
Unwind is a very important pipeline stage in the aggregation framework. Its help us transform complex and nested documents into flat and simple, and that help us to query the data in different ways.
What's the $unwind operator in MongoDB?
In my collection posts I've documents like this
[{
_id : ObjectId("post-object-id"),
title : 'Post #1',
category_id : ObjectId("category-object-id")
}]
I need to make some queries where I those a range of posts based on their category_id (can be multiple ids) but exclude some of them.
I've tried with the query (in shell):
db.posts.find({$and: [
{_id: { $nin : ['ObjectId("post-object-id")']}},
{category_id : { $in : ['ObjectId("category-object-id")']}}
]})
I returns 0 if count().
However, if I change the category_id attribute and remove the $in and just include one ID it work, like this:
db.posts.find({$and: [
{_id: { $nin : ['ObjectId("58a1af81613119002d42ef06")']}},
{category_id : ObjectId("58761634bfb31efd5ce6e88d")}
]})
but this solution only enables me to find by one category.
How would I got about combining $in and $nin with objectId's in the same manner as above?
This will work, just remove single quotes around ObjectId
db.posts.find({$and: [
{_id: { $nin : [ObjectId("post-object-id")]}},
{category_id : { $in : [ObjectId("category-object-id")]}}
]})
You should not put single quotes around ObjectId, it make them strings
I need to query my users collection for new users that started after the date "2015-11-20" returning only unique emails.
Here's a sample of the structure:
{
"_id" : ObjectId("abcd123"),
"user_name" : "My Name",
"last_name" : "Name",
"first_name" : "My",
"email" : "my.name#gmail.com",
"user_type" : "general",
"joining_date" : ISODate("2015-11-20T14:56:57.165Z")
}
Here's my query thus far, I'm not sure how it's making sure, if even, that only unique emails are returned.
db.users.aggregate([{$match: {"joining_date": {$gt: ISODate("2015-11-20")}}},{$group: {_id:{email: "$email", "first_name": "$first_name", "last_name": "$last_name", "user_name": "$user_name"}}}]).pretty();
Instead of aggregation you can use distinct method of collection. So from the above example your distinct query will look like:
db.users.distinct('email', {"joining_date": {$gt: ISODate("2015-11-20")}}
The above query returns an array of email based on the condition.
Your aggregation query wont return you unique emails as you are grouping by email, user_name, first_name and last_name. This will return the unique combination of them. If you were only grouping by email then you will get the unique mail ids. But then all the mail ids will be in separate document and you need to iterate over the result set. There is a similar aggregate query similar to the distinct method shown above.
db.users.aggregate([
{$match: {"joining_date": {$gt: ISODate("2015-11-20")}}},
{$group: {_id:null, emailIds: {$addToSet : "$email"}}}
])
db.collectionName.aggregate([
{$group:{_id:"$distinctcolumnname", count: {$sum:1}}},
{ $match:{"datecolumnname": { $gte : "21-08-2016 00:00:00" ,$lte :"21-08-2016 09:59:59"}}}]);```
I have the following collection cidade on my MongoDB database:
{
"_id" : 0,
"nome" : "CIDADE0",
"qtdhab" : 1231043
}
So, here's what I want to do. I'm trying to do the equivalent of this SQL query in MongoDB:
SELECT MAX(QTDHAB) FROM CIDADE WHERE QTDHAB <= (SELECT AVG(QTDHAB) FROM CIDADE);
Basically, I want the biggest value of the field qtdhab from the collection cidade which follows the condition of being lower than the average value of the same field qtdhab on the same collection cidade. So, I have mapped this into 3 queries, like this:
var resultado = db.cidade.aggregate({"$group": {"_id": null, "avgHab": {"$avg": "$qtdhab"}}}).toArray()
var resultado2 = db.cidade.find({qtdhab: {$lte: resultado[0].avgHab}}).toArray()
resultado2.aggregate({"$group": {"_id": null, "maxHab": {"$max": "$qtdhab"}}})
The problem is, as I found out the hard way, that there is no .aggregate method for an array such as resultado2, so the last query returns an error. Is there any other way for me to get the biggest value for the field qtdhab out of this array of documents that was generated by these 2 queries?
You can achieve this by using only one query(aggregation):
db.cidade.aggregate([
/*find the avg and keep also the aggregated field*/
{"$group": {
"_id": null,
"qtdhab" : {"$push" :"$qtdhab"},
"avgHab": {"$avg": "$qtdhab"}
}},
/*unwind the array*/
{$unwind: "$qtdhab"},
/*get the max from the fields less than the avg*/
{"$group": {
"_id": null,
"res" : {"$max" : {$cond :[{$lte :["$qtdhab", "$avgHab"]}, "$qtdhab", null]} },
}}
])