MongoDB compound index order of the fields - mongodb

I have collection schema
1) user
2) age
3) role
I have created compound index ( { age: 1, user: 1 } ). When I find documents with criteria { age: { $gt: 21, $lt: 50 }, user: 'user124' }, the index is properly used ( I am watching in explain()), but when I change order to { user: '124', age: { $gt: 21, $lt: 50 } } results and index usage is identical. When I have compound index on two fields, order in criteria doesn't matter?

This is correct, the order does not matter.
In fact, only arrays in the query are ordered and dictionarys are not.
http://json.org/

Related

How to find all documents from partial index in mongoDB?

Suppose I have a database users with a partial index:
db.users.createIndex(
{ username: 1 },
{ unique: true, partialFilterExpression: { age: { $gte: 21 } } }
)
I want to find all documents for query:
db.users.find(
{age: { $gte: 21 }}
)
However, this query will not use my index despite the fact that all I need is to find all documents from the index.
What should I do to use this index for my purpose?
Try this query
db.users.find({ username:{ $ne:null }, age:{ $gte: 21 }})
If you have null users, try:
db.users.find({$or:[{username:{ $ne:null}},{username: {$eq:null }}], age:{ $gte: 21 }})
Considerations
MongoDB requires the indexed field to be in the query, to use an index
There may be other suitable conditions ($exists won't work), but I find this useful enough.
Add .explain() to see the parsed Query and the usage of Indexes.
Tested
I guess this one should also work (but I did not test):
db.users.find({}).min({}).hint({ username: 1 })

MongoDB - Filter on First Field of a Two Field Compound Index and Sort on the Second Field?

I am inserting data into my MongoDB collection of the following format.
{'customer_id': 1, 'timestamp': 200}
{'customer_id': 2, 'timestamp': 210}
{'customer_id': 3, 'timestamp': 300}
I have a compound index created with keys: { 'customer_id': 1, 'timestamp': -1 }
db.collection.createIndex( { customer_id: 1, timestamp: -1 } , { name: "query for inventory" } )
Now, I need to filter such that I get the documents with customer_id = 1 or 2 and then sort the documents on the timestamp (in descending format, that is the latest will be at the top).
My query looks like this:
db.collection.find( { 'customer_id': { '$in': [ 1, 2 ] } } ).sort( { 'timestamp': -1 } ).limit( 100 )
I know how to do the query but I am unsure if I should be using this Compound Index or using two Indices on the separate fields or both.
It would be really helpful if I could get a clarification on which approach to use and why that approach is better.

Mongoose Query to Find Unique Values

In my MongoDB backend I want to create an endpoint that returns all the unique values for a property called department. Now, if I were doing this in IntelliShell I would just do something like:
db.staffmembers.distinct( "department" )
This will return an array of all the values for department.
But how do you return all unique values within a Mongoose find() query like this one?
Staffmember.find({ name: 'john', age: { $gte: 18 }});
In other words, what would the syntax look like if I want to use a find() like above, to return all unique values for department within the "staffmembers" collection?
You can use .aggregate() and pass your condition into $match stage and then use $addToSet within $group to get unique values.
let result = await Staffmember.aggregate([
{ $match: { name: 'john', age: { $gte: 18 }} },
{ $group: { _id: null, departments: { $addToSet: "$department" } } }
]);
We can use find and distinct like this for the above scenario. Aggregate might be a little overkill. I have tried both the solutions below.
Staffmember.find({name: 'john', age: {$gte: 18}}).distinct('department',
function(error, departments) {
// departments is an array of all unique department names
}
);
Staffmember.distinct('department', {name:'john', age:{ $gte: 18 }},
function(error, departments) {
// departments is an array of all unique department names
}
);
This link just nails it with all different possibilities:
How do I query for distinct values in Mongoose?

What is difference between partial indexes and sparse indexes mongodb?

I've read official docs of MongoDB but really can't understand the difference between sparse and partial indexes. I wanted to have an explanatory view with examples.
Sparse index is an optimized index which only contains pointers to documents that have value(s) in the indexed fields.
For example, let's say you would like to add an index on lastname field
{ _id: 1, firstname: 'John', lastname: 'Black', age: 20 }
{ _id: 2, firstname: 'Stive', lastname: 'White', age: 17 }
{ _id: 3, firstname: 'Tom', age: 22 }
if you run
db.users.createIndex({ lastname: 1 });
command, it will add indexes on 3 documents, but you don't need to have an index on a document where is no lastname value (_id: 3); it's a waste of space and memory.
To avoid empty fields' indexing, mongodb has sparse index, which is simply "check for non-empty value".
So when you add sparse: true
db.users.createIndex({ lastname: 1, sparse: true });
Mongodb will add indexes only for 2 documents (_id: 1, _id:2). Its great, but what if you want to index only those users' documents which are older than 18 years?
You cant use sparse index because it only checks documents for value existence.
This is why partial indexes were created.
db.person.createIndex(
{ age: 1},
{ partialFilterExpression: { age: { $gte: 18 }, lastname: { $exists: true }}
);
This example will put index only for 1 document(id: 1). Partial index is complex version of sparse, it will filter documents not only checking their existence, but using conditions provided in partialFilterExpression field.

Matching on compound _id fields in MongoDB aggregate

I'm a MongoDB novice so please forgive me if this question has an obvious answer...
Context:
I've followed the example in the MongoDB docs to implement hierarchical aggregation using map-reduce. The example uses a "compound" _id field as a map-reduce key producing aggregate documents like this...
{
_id: { u: "rick", d: ISODate("2010-10-10T14:00:00Z") },
value: {
ts: ISODate('2010-10-10T15:01:00Z'),
total: 254,
count: 10,
mean: 25.4 }
}
This is all well and good. My particular use case requires that values for several similar keys be emitted each map step. For example...
{
_id: { u: "rick", d: ISODate("2010-10-10T14:00:00Z"), hobby: "wizardry" },
value: {
ts: ISODate('2010-10-10T15:01:00Z'),
total: 254,
count: 10,
mean: 25.4 }
}
{
_id: { u: "rick", d: ISODate("2010-10-10T14:00:00Z"), gender: "male" },
value: {
ts: ISODate('2010-10-10T15:01:00Z'),
total: 254,
count: 10,
mean: 25.4 }
}
(The values are the same, but the _id keys are slightly different.)
This is also well and good.
Question:
Now I'd like to aggregate over my hierarchical collections (views), which contain documents having several different compound _id fields, but only over documents with $matching _id fields. For example, I'd like to aggregate over just the documents possessing the {u: String, d: Date, hobby: String} type _id or just the documents with an _id of type {u: String, d: Date}.
I'm aware that I can use the $exists operator to restrict which _id fields should and shouldn't be permitted, but I don't want to have to create a separate aggregation for each _id (potentially many).
Is there a simple way of programmatically restricting $matching documents to those containing (or not containing) particular fields in an aggregate?
I think the best way to address this issues is by storing your data differently. Your "_id" sort of has arbitrary values as key and that is something you should avoid. I would probably store the documents as:
{
_id: { u: "rick", d: ISODate("2010-10-10T14:00:00Z"), type: hobby, value: "wizardry" }
}
{
_id: { u: "rick", d: ISODate("2010-10-10T14:00:00Z"), type: gender, value: "male" },
}
And then your match because simple even without having to create a different match for each type.