Scenario
Let’s say we have a collection of documents representing books in a library. Each book document has a genres
field, which is an array of strings representing the genres that the book belongs to. We want to find all books that belong to either the “Mystery” or “Thriller” genres.
Solution
In this case, we can use the $in
operator to specify that we want to find books where the genres
field contains at least one of the specified values. Here’s an example query using Mongoose:
Book.find({ genres: { $in: ["Mystery", "Thriller"] } });
This query will return all books that have either “Mystery” or “Thriller” (or both) in their genres
field.
Now, let’s say we want to find all books that belong to both the “Mystery” and “Thriller” genres. In this case, we can use the $all
operator to specify that we want to find books where the genres
field contains all of the specified values. Here’s an example query using Mongoose:
Book.find({ genres: { $all: ["Mystery", "Thriller"] } });
This query will return all books that have both “Mystery” and “Thriller” in their genres
field.
Let's Understand with another example:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const orderSchema = new Schema({
products: [String]
});
const Order = mongoose.model('Order', orderSchema);
// Function to create new documents
async function run() {
await Order.create([
{ products: ['product1', 'product2'] },
{ products: ['product1', 'product3'] },
{ products: ['product2', 'product3'] },
{ products: ['product4', 'product5'] },
]);
// Using $in operator
const inQuery = { products: { $in: ['product1', 'product2'] } };
const inOrders = await Order.find(inQuery);
console.log('Orders with product1 or product2:');
console.log(inOrders);
// Using $all operator
const allQuery = { products: { $all: ['product1', 'product2'] } };
const allOrders = await Order.find(allQuery);
console.log('Orders with both product1 and product2:');
console.log(allOrders);
}
run();
Order Schema and Order Model are created.
Now the function run()
will create 4 documents of Order
collections, where each document will carry a field called products
which stores an array of strings.
And then we have two types of queries, the first one using the $in
operator and the second one using the $all
operator.
$in
We used the $in
operator to find orders where the products
array contains either 'product1'
or 'product2'
.
This query { products: { $in: ['product1', 'product2'] } }
returns these orders:
Orders with product1 or product2:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"products": [
"product1",
"product2"
]
},
{
"_id": ObjectId("5a934e000102030405000001"),
"products": [
"product1",
"product3"
]
},
{
"_id": ObjectId("5a934e000102030405000002"),
"products": [
"product2",
"product3"
]
}
]
If you see, only those orders are returned that have either product1
or product2
in their field products, except the only document that has products field that contains: ['product4', 'product5']
$all
Next, we used the $all
operator to find orders where the products
array contains both 'product1'
and 'product2'
.
This query { products: { $all: ['product1', 'product2'] } }
returns only one order, the first one.
Orders with both product1 and product2:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"products": [
"product1",
"product2"
]
}
]
So, the $all
operator returns documents where the values of the array field products
contains all the specified elements: product1
and product2
.
Opposite of $in
The $nin
operator matches documents where the value of a field is not in a specified array. For example, to find all documents in the User
collection where the age
field is not 25
, 30
, or 35
, you can use the following query:
const users = await User.find({ age: { $nin: [25, 30, 35] } });
Opposite of $all
There isn’t a direct opposite of the $all
operator in MongoDB, but you can achieve the same result by combining the $all
and $not
operators.
The $all
operator matches documents where the value of a field contains all the values in the specified array. The $not
operator inverts the effect of a query expression, returning documents that do not match the query criteria.
Here’s an example that demonstrates how to use these two operators together to find all documents in the Order
collection where the products
array does not contain all of the specified elements:
const productsToExclude = ['product1', 'product2'];
const query = {
products: {
$not: {
$all: productsToExclude
}
}
};
const orders = await Order.find(query);
In this example, we use the $all
operator to match Order
documents where all elements in the productsToExclude
array is present in the products
array.
We then use the $not
operator to invert the effect of the $all
operator, returning documents where not all of the elements in the productsToExclude
array is present in the products
array.
In simple terms, combining $not
and $all
operators we get those Order
documents that do not contain product1
and product2
.
Output:
[
{
"_id": ObjectId("5a934e000102030405000001"),
"products": [
"product1",
"product3"
]
},
{
"_id": ObjectId("5a934e000102030405000002"),
"products": [
"product2",
"product3"
]
}
]
Conclusion
In summary, mongoose operators help narrow down the search for our convenience and thus reduce the retrieval time. I suggest experimenting with Mongoose operators or queries in the above code snippets using this playground I have found on the internet.
If you like this article, make sure to leave a reaction and comment if you have any doubts.
Also, follow me on Twitter :)