I have a document that stores an array of ids referencing a different collection:
{
title: 'Title of the document',
categories: [
{ _id: 1 },
{ _id: 2 },
{ _id: 3 },
{ _id: 4 },
]
}
Now I want to be able to find all the documents that have at least one of the categories that I pass into an array:
categories: [1, 3, 4]
I have searched stackoverflow and the MongoDB documentation, but I didn't find how to implement this.
I think the $in operator is what you are looking for. It selects documents where the value of a field equals any value in the specified array. Mongo documentation has a helpful page for it with a section for querying values in an array.
You will also need to use dot notation to query for the _id field of the categories array. The docs also have a page for querying an array of embedded documents, which is what you are doing here (you are querying an array of category documents).
For your case, your query object should probably be something like
{ 'categories._id' : { $in: [1, 3, 4] } }
Related
sorry in advanced I'm new to mongo. I have somewhat of a complex aggregation query that needs to be written. I am needing to go through each record and see how many items from an array that it has on a specific column. E.g.
Imagine I have an array of tags that I want to filter by:
const tags = [1, 2, 3]
I want to figure out how many items from the tags variable that each record contains on a tags column. So if a record contains [1, 2, 3, ...] then the score should be 3, if it contains [1, 2, ...] the score should be 2, etc. It does not need to be exact match, instead I'm simply wanting to know how many tags a record contains from the passed array above. If a record doesn't have any of the tags, I would prefer it to get filtered out but it's not required.
My schema looks like:
const schema = new Schema({
name: {
type: String,
required: true,
},
description: {
type: String,
},
tags: {
type: Array,
},
createdAt: {
type: Date,
default: Date.now,
},
});
My expected result would be an array of items with the score of how many tags it matched:
[
{
name: "$name",
description: "$description",
tags: "$tags"
score: { $sum: 1 }
}
]
It seems you want the size of the array and not the value of the last tag.
You can use $size it counts and returns the total number of items in an array. Take a look at mongodb $size documentation
You can use the setIntersection expression so you can have some thing like score: {$size:{$setIntersection:["$tags", tags]}}
Where the second tags is the one that you want to find. This should do the trick. The setIntersection will return in array with items that are found in both arrays after which you can simply return the size of the array
I have a MongoDB collection called users with documents that look like:
{
_id: ObjectId('123'),
username: "abc",
avatar: "avatar/long-unique-random-string.jpg",
connections: [ObjectId('abc'), ObjectId('xyz'), ObjectId('lmn'), ObjectId('efg')]
}
This document belongs to the users collection.
What I want to do:
First, find one document from the users' collection that matches _id -> '123'.
Project the connections field received from step 1, which is an array of ObjectIds of other users within the same collection.
Find all documents of users from the array field projected in step 2.
Project and return an array of only the username and avatar of all those users from step 3.
While I know that I can do this in two separate queries. First using findOne which returns the friends array. Then, using find with the results of findOne to get all the corresponding usernames and avatars.
But, I would like to do this in one single query, using the aggregation pipeline.
What I want to know, is it even possible to do this in one query using aggregation?
If so, what would the query look like?
What, I currently have:
await usersCollection
.aggregate([
{ $match: { _id: new ObjectId(userId) } },
{ $project: { ids: "$connections" } },
{ $match: { _id: { $in: "ids" } } },
{
$project: {
username: "$username",
avatar: { $ifNull: ["$avatar", "$$REMOVE"] },
},
},
])
.toArray()
I know this is wrong because each aggregation stage receives the results from the previous stage. So, the second match cannot query on the entire users' collection, as far as I know.
I'm using MongoDB drivers for nodeJS. And I would like to avoid $lookup for possible solutions.
I've an array inside document lets say user has followedBy array I want to find a user based on ID and then want to retrieve only first 3 elements of followedBy.
In picture you can see I have users collection and then inside user I've an array named as followedBy.
I need to search a user first based on Id and then to retrieve first 3 elements of array in a single query rather than fetch user first and get followedBy array having thousands of members inside it and then apply slice on it.
According to docs you can use $slice into projection.
So you have to do:
db.collection.find({
"_id": your_id
},
{
"followedBy": {
"$slice": 3
}
})
Check this example.
Using mongoose is exactly the same query:
YourModel.find({
"id": your_id
},
{
"followedBy": {
"$slice": 3
}
})
.then(result => {
// ...
}).catch(e => {})
I am using mongoDB and nodejs
I have 4 collections
collection 1 is teacher with fields teacher_id, teacher_name
collection 2 is subject with fieldssubject _id, subject_name
collection 3 is book with fields book_id, book_name
collection is student which have fields -- _id, student_name, teacher_id, subject_id, book_id
how can I fetch ids from 1, 2, 3 collections simultaneously and insert to corresponding id in collection
I have tried some which always ask for a matching field... is ther any function which returns data from collection even though no match field?
can someone please help
Well, in that case, you need to fetch all the documents from those collections. That will be a bit costly aggregation but I'm adding here in code:
Firstly, I'm grouping on null, to avoid to attach lookup value to every single document in teacher collection.
db.teacher.aggregate([
{
$group:{
"_id":null,
"root":{
$push:"$$ROOT"
}
}
},
{
$lookup:
{
from:"subject",
pipeline: [],
as: "subjectLookup"
}
},
{
$lookup:
{
from:"book",
pipeline: [],
as: "bookLookup"
}
},
{
$lookup:
{
from:"student",
pipeline: [],
as: "studentLookup"
}
}
]).pretty()
These lookups will give the array which contains all the documents from respective collections, you can limit the documents by adding $match stage in the pipeline of lookup stage.
Hope this will solve your problem :)
query to find all the elements in the array in mongoose dynamically
below is the object
var res1= {
"category":["travel","cafe"],
"amount":"300"
}
There could be more elements in the category but I want to create the query which automatically finds all the elements in the database just like forEach works
The $in operator should to the trick. $in will look for documents where the provided field matches any of the values in the array. the query would look like this:
Detail.find({
category: { $in: ["travel", "cafe"] },
amount: 300
})
assuming the filters are coming in dynamically on the request, and that req.body.categories is an array of desired categories:
Detail.find({
category: { $in: req.body.categories },
amount: req.body.amount
})