Getting directly an array from a mongoose model - mongodb

I'm trying to query directly to an array inside of an mongoose document, but for the moment i have couldn't.
The document example:
{
_id:62141a799b646c7926fcfa9c
firstname:"firstname"
lastname:"lastname"
username:"username"
phone:"0000-0000000"
email:"Example#mail.com"
email_verified_at:null
password:"$2a$10$LUATvtyPmlojHVdCkxP/QO9UUzQgOoGCW6xyx8YPUZkt5l7j6kHxK"
remember_token:null
deleted_at:null
created_at:2022-02-21T23:04:25.097+00:00
updated_at:2022-02-21T23:04:25.097+00:00
notes: [
"621954b8f073154099b92fca"
"62142c426ca950e33baa1302"
]
I have a query that works but i think that isn't the most optimal approach, altough i could be wrong.
I want to get something like this:
[
"621954b8f073154099b92fca"
"62142c426ca950e33baa1302"
]
or populated:
[
{
_id: new ObjectId("621954b8f073154099b92fca"),
user: new ObjectId("62141a799b646c7926fcfa9c"),
type: new ObjectId("62076ce385b4eea8c5aeb8ba"),
title: 'qwasdasd',
content: '',
created_at: 2022-02-25T22:14:16.515Z,
updated_at: 2022-02-25T22:14:16.515Z
},
{
_id: new ObjectId("62142c426ca950e33baa1302"),
user: new ObjectId("62141a799b646c7926fcfa9c"),
type: new ObjectId("62076ce385b4eea8c5aeb8ba"),
title: 'qwasdasd',
content: '',
created_at: 2022-02-25T22:14:16.515Z,
updated_at: 2022-02-25T22:14:16.515Z
}
]
And even if i need to find an specific field, search it, but with the query:
const notes = await collection.findOne({ _id: '62141a799b646c7926fcfa9c', notes: { _id: '621954b8f073154099b92fca' } }, { 'notes.$._id': true });
i have this rersult:
{
_id: new ObjectId("62141a799b646c7926fcfa9c"),
notes: [
"621954b8f073154099b92fca"
]
}
or populated:
{
_id: new ObjectId("62141a799b646c7926fcfa9c"),
notes: [
{
_id: new ObjectId("621954b8f073154099b92fca"),
user: new ObjectId("62141a799b646c7926fcfa9c"),
type: new ObjectId("62076ce385b4eea8c5aeb8ba"),
title: 'qwasdasd',
content: '',
created_at: 2022-02-25T22:14:16.515Z,
updated_at: 2022-02-25T22:14:16.515Z
}
]
}
And i know that i can reach it filtering the ObjectId from user with '-_id notes.$._id' instead of { 'notes.$._id': true } and then destructuring the main object with a const { notes } resulting in this code:
const { notes } = await collection.findOne({ _id: '62141a799b646c7926fcfa9c', notes: { _id: '621954b8f073154099b92fca' } }, '-_id notes.$._id' );
But, it's the best approach to do this? Could i do it in different way being able to take advantage of findOne options like, skip, etc...?
PD: If there's some error it's because it's not the original code, i have modified it because in original code there're many abstractions.
Thanks in advance.

Related

How can I get count of document in one to many relation with mongoose

I have two schemas.
// tutorial
export const TutorialSchema = new mongoose.Schema({
title: String,
author: String,
tags: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Tag"
}
]
})
// tag
export const TagSchema = new mongoose.Schema({
name: String,
companyId: Number
})
constructor(#InjectModel('Tutorial') private readonly _tutorialModel: Model<any>) { }
I want to get count of tags for each tutorial (in one query). How can I do that ?
I know how to get list of tutorial.
const result = await _tutorialModel.find()
You can use group aggregation in the following way -
_tutorialModel.aggregate([
{
$project: {
title: 1,
_id:1,
numberOfTags: { $cond: { if: { $isArray: "$tags" }, then: { $size: "$tags"
}, else: "NA"} }
}
}
] )
For Size operator you need to ensure first that tags is always an array! If for any reason tags is not present then error will be thrown.
If you make sure tags will be always present and is an array then you can simplify to following -
_tutorialModel.aggregate([
{
$project: {
title: 1,
_id:1,
numberOfTags: {$size: "$tags"}
}
}
] )
Take a look at -
Size aggregation operator -
https://www.mongodb.com/docs/manual/reference/operator/aggregation/size/

Mongoose - projection with $elemMatch on nested fields

I'm relatively new to MongoDB/Mongoose and I've only performed simple queries. Now I'm having some trouble trying to filter my database in a slightly more complex way. I already did some research to tackle my previous issues, but now I can't move forward. Here's what happening:
This is my schema:
const userSchema = new mongoose.Schema({
email: String,
password: String,
movies: [
{
title: String,
movieId: Number,
view_count: Number,
rating: Number,
review: String,
},
],
lists: {
watched_movies: [
{
title: String,
director: String,
genres: [{ type: String }],
runtime: Number,
date: Date,
},
],
},
});
I want to make a GET request that matches simultaneously "lists.watched_movies": { _id: req.params.entryId } and also "movies.title": req.body.title for a given email, so that the outcome of the findOne query would be just those elements and not the whole document. What I'm trying to accomplish is something like that:
{
email: "some.email#gmail.com",
movies: [
{
title: "Mongoose Strikes Back",
movieId: 123,
view_count: 1,
rating: 3,
review: "Very confusing movie!"
}
],
lists: {
watched_movies: [
{
_id: 4321
title: "Mongoose Strikes Back",
director: "Mongo",
genres: ["Drama"],
runtime: 150,
date: "2021-11-22"
}
]
}
}
My first attempt to tackle it, however, wasn't successful. Here's what I tried:
router.route("/:entryId").get((req, res) => {
User.findOne(
{ email: "some.email#gmail.com" },
{
"lists.watched_movies": { $elemMatch: { _id: req.params.entryId } },
movies: { $elemMatch: { title: req.body.title } },
},
(err, entry) => {
if (!err) {
res.send(entry);
console.log(entry);
} else {
console.log(err);
}
}
);
});
It says that Cannot use $elemMatch projection on a nested field. I thought that maybe I can solve it by changing my schema, but I'd like to avoid it if possible.
For your scenario, you can use $filter to filter document(s) in nested array field.
db.collection.find({
email: "some.email#gmail.com"
},
{
"lists.watched_movies": {
"$filter": {
"input": "$lists.watched_movies",
"cond": {
"$eq": [
"$$this._id",
4321// req.params.entryId
]
}
}
},
movies: {
$elemMatch: {
title: "Mongoose Strikes Back"// req.body.title
}
}
})
Sample Mongo Playground

MongoDB - remove many from arrays of all existing elements

I have some simple user data. Here is example for one user:
const userSchema = new Schema({
userName: {
type: String,
},
projectsInput: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
projectsHold: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
});
I want by having ProjectId to be able to remove all records from all users that contains it.
if I get the first one
60f02d21159c4b4110f21a32
how I can perform updateMany function for my UserModel?
return UserModel.updateMany(
{
projectsInput: {
$elemMatch: args.projectId,
},
},
{
projectsInput: {
$slice: [projectsInput.$, 1],
},
}
);
})
Here is my code that is not working.
args.projectId = 60f02d21159c4b4110f21a32 (my id for the project I want to delete)
and UserModel is my mongodb Schema for user.
you can use $pull
{
$pull: {
projectsInputs: "123"
}
}

Find if an array present in the mongo Database

This is my Conversation Schema
const ConversationSchema = new Schema({
recipients: [{ type: Schema.Types.ObjectId, ref : 'User' }],
lastMessage: {
type: String,
default: ''
},
date: {
type: Date,
default: Date.now()
},
})
I want to know if there exist an array [ patientId, doctorId ]
Here is my main approach to find
I am not able to get the response and I already have one document with that same array
const conversationBetween = await Conversation.findOne(
{
recipients: {
$all: [
{ $elemMatch: { $eq: patientId }},
{ $elemMatch: { $eq: doctorId }}
],
}
}
)
if (conversationBetween) {
return res.status(401).json({
status: "failed",
message: "You already have a conversation with this doctor"
});
}
following Code to add a Conversation in the Conversation Collection, this works fine
const newConversation = new Conversation({
recipients: [ patientId,doctorId ],
lastMessage: `I want to get consultation`,
date: Date.now(),
})
await newConversation.save()
res.status(200).json({
status: "success",
message: "Conversation added successfully",
conversation: newConversation
});
The main purpose is to make sure that if there present an entry with [ patientId, doctorId ] in Conversation it should not make a new entry..
But at this time its not able to find and is making that same entry.
You can do this
await Conversation.findOne(
{
recipients: [patientId, doctorId]
}
)
Working in Playground

Meteor Mongo adding data to an existing collection

I currently have the the collection "Plans" and it is made upon the creation of a form submit. It inserts the following:
Plans.insert({
location,
address,
date,
time,
notes,
createdAt: new Date(), // current time
owner: Meteor.userId(),
username: Meteor.user().username,
attendees: [
{
attender: [{
user: String,
attending: Boolean,
}],
},
],
});
Then, upon a click of a checkbox, I want a new attender object to be added to the attendees array. So far I have tried to do:
'click .notattending'() {
Plans.insert(
{_id: this._id,
attendees: [{
attender: [
{
user: Meteor.user().username,
attending: false,
}
],
}
]
},
);
},
However it isn't adding to the Mongo collection. Is this the correct way to go about doing it?
You can try this to based on your schema.
Plans.update({ _id: this._id }, {
$push: {
attendees: { user: "", attending: true },
},
});