How to add text to a MongoDB count query - mongodb

I'm trying to get a text output added to query to count the number of employed personnel in a DB. I'm using income exists and an indicator that personnel is employed.
My input is
db.collection.countDocuments({income{$exists:true)}, {as: {"Number Employed:"}})
Any thoughts on why this isn't working?

The countDocuments function returns a number, not a document. The second argument is an options object, not a projection. The valid options are limit, skip, hint, and maxTimeMS.
If you need to return a document with a specific field name, use aggregation:
db.collection.aggregate([
{$match: {income{$exists:true}}},
{$count: "Number Employed"}
])

Related

range operator not returning expected results via mongodb database

I've now tested this via the shell, Studio 3T IDE and within my API itself.
The first query looks something like this:
Notification.find({
userId: ObjectId("...")
}).limit(20).sort('-createdAt')
which returns the following documents sorted by their createdAt timestamp (which is also imbedded in the _id field):
I then run the next query which I would expect to return the results starting at _id: ObjectId("615869eac849ec00205aa112"):
Notification.find({
userId: ObjectId("..."),
_id: { $lt: ObjectId("615869eac849ec00205aa115"}
}).limit(20).sort('-createdAt')
I would expect this command to get me my next 20 results sorted in the same descending order as the original query above. However, I get the following:
which has 3 results from the original query. The _id field is clearly unique between the _id I use as a cursor and the incorrectly returned results but after inspection the createdAt timestamp is the exact same as the createdAt timestamp of the document _id I use for the range query.
The problem is you are querying on an unsorted field expecting that value to identify a specific point the result set.
Note that in the first result set entries 17 through 29 all have the same epoch timestamp in the _id value, and that those 13 entries are not in any particular order.
As luck would have it, entry 20 has the greatest _id of that group, so all 12 of the others are lesser, even the ones that happened to come before.
To make this work, also sort on _id like:
.sort({createdAt: -1, _id: -1})

How to project in MongoDB after sort?

In find operation fields can be excluded, but what if I want to do a find then a sort and just after then the projection. Do you know any trick, operation for it?
doc: fields {Object}, the fields to return in the query. Object of fields to include or exclude (not both), {‘a’:1}
You can run a usual find query with conditions, projections, and sort. I think you want to sort on a field that you don't want to project. But don't worry about that, you can sort on that field even after not projecting it.
If you explicitly select projection of sorting field as "0", then you won't be able to perform that find query.
//This query will work
db.collection.find(
{_id:'someId'},
{'someField':1})
.sort('someOtherField':1)
//This query won't work
db.collection.find(
{_id:'someId'},
{'someField':1,'someOtherField':0})
.sort('someOtherField':1)
However, if you still don't get required results, look into the MongoDB Aggregation Framework!
Here is the sample query for aggregation according to your requirement
db.collection.aggregate([
{$match: {_id:'someId'}},
{$sort: {someField:1}},
{$project: {_id:1,someOtherField:1}},
])

MongoDB: Update field with size of embedded array

I have a collection of documents with an array (set in this case): my_array
I'm adding things to this set periodically
collection.find({ "_id": target_id })
.upsert().update({ '$addToSet':{ 'my_array': new_entry }})
Many of the logical operations I perform on this DB are based on this sub-array's size. So I've created a field (indexed) called len_of_array. The index is quite critical to my use case.
In the case where this is a true array and not a set, the $incr would work beautifully in the same update
However, since the sub-collection is a set, the length of the collection, my_array, may or may not have changed.
My current solution:
Call this periodically for each target_id, but this requires performing a find in order to get the correct len_of_array
collection.find({ '_id': target_id})
.upsert().update({ '$set':{ 'len_of_array': new_length }})
My Question
Is there a way to set a field of a document to the indexed size of a sub-array in the same document in a single update?
You don't need the field length_of_array in order to query by its size. There is the $size operator. Which would save you the periodical update, too.
Let's say you want to find all documents for which the length of my_array is greater than 2:
db.coll.find({ "my_array":{ "$size" :{ "$gt": 2 }}})

Why does db.collection.find({}).maxTimeMS(100) return everything, but db.collection.find({}, {$maxTimeMS: 100}) only returns object IDs?

I'm using MongoDB 2.6.8. According to the $maxTimeMS reference, these two queries should behave identically:
> db.collection.find({}).maxTimeMS(100)
> db.collection.find({}, {$maxTimeMS: 100})
The first query does exactly what I want, but the second query restricts only returns the object IDs of the documents. I tried increasing $maxTimeMS to 100000000 and there was no change in behavior.
Why am I getting different results for these two commands?
You found a bug in the documentation.
The reason that db.collection.find({}, {$maxTimeMS: 100}) returns only the _id of each object is because mongoDB is interpreting the {$maxTimeMS: 100} portion of the query as a projection.
So it thinks you want to see all the documents and you want to see the fields _id and the field $maxTimeMS. Of course, none of your documents have a $maxTimeMS field, so they only show the _id.
The proper way to perform the query you want without the shortcut is:
db.collection.find({ $query: {}, $maxTimeMS: 100 })

How do I specify criteria for excluding documents from a query?

This seems like a simple enough question but I haven't found an answer:
I'm using MongoDB and I want to perform a query in which I provide search criteria, but I also want to carve out an exception where certain documents are excluded based on criteria. For example, imagine a collection with the fields name, age and gender.
Retrieving everyone below a certain age? Easy: <collection>.find({'age':{'$lt':<maxAge>}})
Retrieving all females below a certain age? Piece of cake: <collection>.find({'gender':female, 'age':{'$lt':<maxAge>}})
But what about retrieving everyone, except if they are [female and below a certain age?]. You can easily negate a specific field with the '$ne' operator, but how do I negate everyone who matches a set of criteria?
You would have to apply boolean logic to invert the AND into an OR of the negation of each term individually:
collection.find({$or: [{age: {$gte: maxAge}}, {gender: {$ne: 'female'}}]})
or
collection.find({$or: [{age: {$not: {$lt: maxAge}}}, {gender: {$ne: 'female'}}]})