MongoDB Select documents by the value of a specific field - mongodb

MongoDB - userModel (simplified)
{
_id: "exampleid1",
name: "examplename1",
following: [
{
_id: "exampleid2",
name: "examplename2"
},
{
_id: "exampleid3",
name: "examplename3"
}
],
followers: [
{
_id: "exampleid4",
name: "examplename4"
},
{
_id: "exampleid5",
name: "examplename5"
}
]
}
Hey,
I'm building a social media platform and I need to get from the database only the users that I follow.
I tried the query below, but gives me nothing:
User.find( { "followers": { _id: "exampleid1"} } )

Try to divide the document selection ({_id: "exampleid1"}) from the projection ({followers: 1, _id: 0}):
db.collection.find({
_id: "exampleid1"
},
{
followers: 1,
_id: 0
})
See how it works on the playground example

Related

Extract list of data from collections

I have a list of collection like the following in mongodb
{ _id: ObjectId("6087feeef467a4320883daf3"),
name: 'group 1',
admins: ['adam', 'ken']
}
{ _id: ObjectId("2087feeef467a4320883daf3"),
name: 'group 2',
admins: ['rebecca']
}
{ _id: ObjectId("9987feeef467a4320883daf3"),
name: 'group 3',
admins: []
}
I need to extract out all the admins, the end result would be something like this:
[
'admin',
'ken',
'rebecca'
]
How can i do that, i stuck at this part:
db.data.find({ admins: { $exists: true, $not: {$size: 0} } })
This will show all collections, but i just need the list
The proper way of doing so using single query is unwinding the array of admins and adding them to a new set.
db.collection.aggregate([
{
$unwind: "$admins"
},
{
$group: {
_id: null,
adminsSet: {
$addToSet: "$admins"
}
}
}
])
The end result will be the following so you could extract your flattened array:
[
{
"_id": null,
"adminsSet": [
"ken",
"rebecca",
"adam"
]
}
]
Mongo playground ref: https://mongoplayground.net/p/LFYsqHdTucN
You can do something like this
db.data.aggregate([
{$unwind: "$admins"},
{$project:{_id:0}}
]).map(x => x.admins);
Result
[
"adam",
"ken",
"rebecca"
]

filter by subdocument while showing all parent document mongoose mongodb

This is the schema model
const tokoSchema = new mongoose.Schema({
name: String
product: [{display: Boolean}]
}
So, what I want is filtering the data by product.display. When I filtered it using toko.find({"product.display": true}) it only shows list of toko that has product.display: true but what I want is if the product display is false it keep showing the _id and name of toko with empty array of product []. Example query expected
// showing all tokos
[
{
_id: blabla
name: "test",
product: [{_id: blabla, display: true}], // filter display:true
},
{
_id: blabla,
name: "test",
product: [] // no product with display:true
}
]
example of toko.find({"product.display": true}) query
// not showing all tokos
[
{
_id: blabla
name: "test",
product: [{_id: blabla, display: true}]
},
]
any solution for this? should I use aggregate?
You need $filter for an array:
db.toko.aggregate([
{
$addFields: {
product: {
$filter: {
input: "$product",
cond: {
$eq: [ "$$this.display", true ]
}
}
}
}
}
])
Mongo Playground

Mongoose pull nested array

My user schema is
{
widgets: [
{
commands: [
{
name: 'delete'
}
]
}
],
name: 'John',
}
and I want to delete widgets.commands by id. I use mongoose. I know the id but when I make the pull request it doesn't delete it.
$pull: {widgets.$.commands: {_id: req.params.id}} Any suggestions?
Here you go
update({}, {
$pull: {
'widgets.commands._id': req.params.id,
},
});
$pull mongoDB documentation
#example from doc
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )

MongoDB: Find and then modify the resulting object

is it possible in MongoDB to find some objects that match a query and then to modify the result without modifying the persistent data?
For example, let
students = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 22 },
{ name: "Carol", age: 19 },
{ name: "Dave", age: 18}
]
Now, I want to query all students that are younger than 20 and in the search result, I just want to replace "age: X" with "under20: 1" resulting in the following:
result = [
{ name: "Carol", under20: 1 },
{ name: "Dave", under20: 1}
]
without changing anything in the database.
Sure, it is possible to get the result and then call a forEach on it, but that sounds so inefficient because I have to rerun every object again, so I'm searching for an alternative. Or is there no one?
A possible solution would be to use an aggregation pipline with a $match followed by a $project:
db.students.aggregate(
[
{
$match: { age: { $lt: 20 } }
},
{
$project:
{
_id: false,
name: true,
under20: { $literal: 1 }
}
}
]);
The $literal: 1 is required as just using under20: 1 is the same as under20: true, requesting that field under20 be included in the result: which would fail as under20 does not exist in the document produced by the match.
Or to return all documents in students and conditionally generate the value for under20 a possible solution would be to use $cond:
db.students.aggregate(
[
{
$project:
{
_id: false,
name: true,
under20:
{
$cond: { if: { $lt: [ "$age", 20 ] }, then: 1, else: 0 }
}
}
}
]);

Mongodb how to use $elemMatch to limit results

My problem is: I have a structure similar to this:
{
id: 1,
participants: [
{ name: "joe", status: 0 },
{ name: "james", status: 2}
],
content: "mongomongo"
}
{
id: 2,
participants: [
{ name: "joe", status: 1 },
{ name: "jordan", status: 3}
],
content: "dongodongo"
}
What I want to do is run a query with almost the same effect as this:
db.find({ '_id': { $in: someArray}}, { participants: {$elemMatch: {'name': someName }}}
I would specify an array of object IDs for the $in, and then I would provide an username. What happens is that it would give me back both objects, but the participants array only has the entry that the $elemMatch found:
{
id: 1,
participants: [
{ name: "joe", status: 0 }
]
}
{
id: 2,
participants: [
{ name: "joe", status: 1 }
]
}
This is what I want, but the part that I DON'T want is that it leaves out other fields (namely content). How can I adjust the query so it that still returns one field in the participants array, but also returns the other fields such as content?
Thank you in advance!
Actually found the solution to my question. Just had to tweak the original query I used. I had confused the projection field and the options field since I was using Mongoose to manage mongodb interactions.
Here's the query that works:
db.find({ '_id': { $in: someArray}}, { participants: {$elemMatch: {'name': someName }}, content: 1, [anything] : 1});
EDIT:
I misunderstood the original post and example. If the only other field you are worried about returning is 'content', then you could add it to the projection argument like so:
db.collection.find(
{
'_id': {
$in: someArray
}
},
{
'participants': {
$elemMatch: {
'name': someName
}
},
'content' : 1
}
)
Hope this helps!