How to delete an object from an array in a mongoose Schema? - node.js

User Schema
const UserSchema = new mongoose.Schema({
name : {
type: String,
required : true
},
email : {
type: String,
required : true
},
password : {
type: String,
required : true
},
date : {
type: Date,
default : Date.now,
},
todo : [{ type : mongoose.Schema.Types.Mixed,ref : 'Todo'}]
})
const User = mongoose.model('User',UserSchema);
module.exports = User;
Todo Schema
const TodoSchema = ({
task : String
})
const Todo = mongoose.model('Todo', TodoSchema)
module.exports = Todo;
Database
How do I delete a single todo object i.e("Task 1") from the user?
router.get('/delete/:id',ensureAuthenticated, (req,res)=>{
id = req.params.id
user = req.user
User.update({ }, { "$pull": { task: id }});
tasks = user.todo
res.render("todo/all",{
todo:tasks,
});
})
I have tried all the stackoverflow threads for over 4 hours and I still coudn't figure out what's wrong. Really apprecitate it if you could help it out.
Thank You :)

Related

Ref in mongoose model not giving output

I am using mongoose for defining schema. I have two schemas user and Userdetail. i want data from user in userdetail
I have below schema but i am not getting the output. i think the code is correct but not getting why there is no output...instead i am getting empty array.
const mongoose = require("mongoose")
const UserDetailSchema = mongoose.Schema({
Phone : {
type : Number
},
FirstName : {
type : String
},
LastName : {
type : String
},
productimage : {
data : Buffer,
contentType : String
},
IsDeleted:{
type:Boolean,
default:false
},
UserID : {
type : String,
},
data : [{
type: mongoose.Schema.Types.ObjectId,
ref: "user"
}],
},
{timestamps: true})
const UserDetail = new mongoose.model("userdetail",UserDetailSchema);
module.exports = UserDetail;
my user schema is,
const mongoose = require("mongoose");
const UserSchema = mongoose.Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
IsDeleted:{
type:Boolean
},
},
{timestamps: true});
module.exports = mongoose.model("user", UserSchema);
query is,
<pre>
router.get("/UserDetail",async (req,res)=>{
try{
const UsersData= await UserDetail.find();
res.json(UsersData)
}catch(e){
res.status(500).json({ message: e.message })
}
})
</pre>
Even though i am using only find, i must get the data with only id right?
Output is -
Any help would be appreciated
router.patch("/UserDetail/:id",Auth,upload.single("productimage"),async(req,res)=>{
try{
const id = req.params.id;
const updatedData = req.body;
updatedData.productimage = {data: fs.readFileSync('upload/' + req.file.filename),
contentType: 'image/png'};
const options = { new: true };
const result = await UserDetail.findOneAndUpdate(
id, updatedData, options
)
res.send(result)
}catch(e){
res.status(500).json({ message: e.message })
}
})
You can populate a field with the populate function:
const userDetails = await UserDetail.find({}).populate('data').exec();
firstly you need a little change in userID in schema of userDetail.Please make it to UserID:{type : mongoose.Schema.Types.ObjectId}, as it will help you in future during aggregation and you can also remove data from your userDetail model as it will not store any data until you save it.And lastly try to run this aggregation query.
const UsersData= await UserDetails.aggregate([
{$lookup:
{
from: "users",
localField: "userID",
foreignField: "_id",
as: "data"
}
}])
In this way your respective details of users will be displayed in array of data.
Make changes in your model and then populate the data.
const mongoose = require("mongoose")
const UserDetailSchema = mongoose.Schema({
Phone : {
type : Number
},
FirstName : {
type : String
},
LastName : {
type : String
},
productimage : {
data : Buffer,
contentType : String
},
IsDeleted:{
type:Boolean,
default:false
},
UserID : {
type : String,
},
data : {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
},
{timestamps: true})
}
populate query
let Model=//import your model here
let userdata=await Model.find().populate("data")
console.log(userdata)

Mongoose - Find document's child array by a specific field

I had spent hours trying to work out how to get records from a document's child array by a specific field, but I failed it.
I would like to pass a personId by a web service to find which meeting he/she has been invited to. As a result, I could track down whether the invitee has accept to join the meeting or not.
Basically, I have the following JSON output:
{
"status": "success",
"requestedAt": "2021-03-28T22:47:03+11:00",
"size": 1,
"meetings": [
{
"invitedMembers": [
{
"isJoined": false,
"_id": "605ffbc00a21ed718c992549",
"person": "a123",
"__v": 0
}
]
}
]
}
with a controller like this:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers.member': memberId
}).populate('invitedMembers');
a meeting model class like below:
const mongoose = require('mongoose');
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'InvitedMembers'
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
and a invitedMembers class like this:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
member: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Member',
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const InvitedMembers = mongoose.model(
'InvitedMembers',
invitedMembersSchmea
);
module.exports = InvitedMembers;
The Member schema only contains a basic personal information such as first name, last name and etc.
I ended up solving my own problem by using a different approach where I changed my data structure by adding invitedMembers as an embedding model in the meeting model and updated the person field in the invitedMembers schema to _id.
Updated Meeting model class:
const mongoose = require('mongoose');
const invitedMembersSchmea = new mongoose.Schema({
_id: {
type: String,
required: true
},
isJoined: {
type: Boolean,
default: false
}
});
const meetingSchema = new mongoose.Schema({
invitedMembers: [
{
type: invitedMembersSchmea
}
]
});
const Meeting = mongoose.model(
'Meeting',
meetingSchema
);
module.exports = Meeting;
As a result, I can find the invited member by ID using the following query:
const memberId = "a123";
const meetings = await Meeting.find({
'invitedMembers._id': memberId
});

Mongoose $gte Date

Why is mongo client returning an answer for the query and Mongoose is not.
db.dates.find({"date_out" : { $gte : ISODate("2018-11-12T00:00:00.000Z") }}).pretty()
{
"_id" : ObjectId("5be8a9eeda7bbc1fc40c1fa1"),
"user" : "some.user#example.com",
"date_in" : ISODate("2018-11-11T22:15:10.095Z"),
"date_out" : ISODate("2018-11-14T22:00:00Z"),
"userId" : "5be5a96e6db7be0568ea6e47"
}
But when I try to do the same query in Mongoose it doesn't return anything
import Dates from "../models/Date";
import moment from 'moment';
const today = moment().startOf('day').toDate(); // 2018-11-11T22:00:00.000Z
const query = { date_out : { $gte : today }};
router.get("/unavailable", (req, res) => {
Dates.find( query )
.then(Booked_Dates => res.json({ Booked_Dates }))
.catch(err => res.status(400).json({ errors: parseErrors(err.errors) }));
});
Also tried const query = { date_out : { $gte : 'ISODate("${today}")' }};
' = `
Can you please point me in the right direction.
PS: If I take out the query it returns the proper result.
Also this is the schema:
import mongoose from "mongoose";
const schema = new mongoose.Schema({
user: { type: String, required: true },
date_in: { type: String, required: true },
date_out: { type: String, required: true },
userId: { type: mongoose.Schema.Types.ObjectId, required: true }
});
export default mongoose.model("Date", schema);

populate with mongoose pagination

i tried to fetch data using npm mongoose-paginate but populate is not working
here is my UsersSchema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var usersSchema = new Schema({
name : String,
created_at : { type : Date, default : Date.now }
});
module.exports = mongoose.model('users',usersSchema);
here is post schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongoosePaginate = require('mongoose-paginate');
var postsSchema = new Schema({
user : { type: Schema.Types.ObjectId, ref: 'users' },
post : String,
created_at : { type : Date, default : Date.now }
});
postsSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('posts',postsSchema);
here is my query
var options = {
sort: { created_at: -1 },
lean: true,
offset: offset,
populate : 'users',
limit: 10
};
postsSchema.paginate({user:user},options,function(err,posts){
if(err){
console.log(err)
return false;
}
console.log(posts)
});
user provide objectID not a users data.
i.e
[{
user : objectID(987654ff11aa),
post : 'post'
}]
If you want to use mongoose-paginate, You can do the following
var query = {};
var options = {
sort: { date: -1 },
populate: 'users',
lean: true,
offset: offset,
limit: 10
};
Post.paginate({}, options, (err, result) => {
//....
})
A populate have following things
Post.find({})
.populate([
// here array is for our memory.
// because may need to populate multiple things
{
path: 'user',
select: 'name',
model:'User',
options: {
sort:{ },
skip: 5,
limit : 10
},
match:{
// filter result in case of multiple result in populate
// may not useful in this case
}
}
])
.exec((err, results)=>{
console.log(err, results)
})

Is it possible to query subdocuments directly using mongoose?

let's say there was a User model and a Post model. In this situation User's would have many posts; User would be the parent and Post would be the child. Is it possible to query for posts directly?
For instance if I wanted to do something like
app.get('/post/search/:query', (req,res) => {
Posts.find({title: req.params.query }, (err,post) => {
res.send(JSON.stringify(post))
})
})
or would one have to do:
app.get('/post/search/:query',(req,res) => {
let resultsFromQuery = [];
User.find({'post.title':req.params.query'}, (err,user) => {
user.posts.forEach((post) => {
if(post.title === req.params.query){
resultsFromQuery.push(post);
}
})
})
res.send(JSON.stringify(resultsFromQuery))
})
EDIT: Here is my schema's.
User Schema (Parent)
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
PostSchema = require('./post.js');
let UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
posts: [PostSchema]
})
module.exports = mongoose.model('User',UserSchema);
Post Schema (Child)
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
let PostSchema = new Schema({
title: {
type: String
},
description: {
type: String
},
image: {
type: String
},
original_poster: {
id: {
type: String,
required: true
},
username: {
type: String,
required: true
}
},
tags: {
type: [String],
required: true
}
})
module.exports = PostSchema;
EDIT:
Here is a sample document
the result of db.users.find({username: 'john'})
{
"_id" : ObjectId("5a163317bf92864245250cf4"),
"username" : "john",
"password" : "$2a$10$mvE.UNgvBZgOURAv28xyA.UdlJi4Zj9IX.OIiOCdp/HC.Cpkuq.ru",
"posts" : [
{
"_id" : ObjectId("5a17c32d54d6ef4987ea275b"),
"title" : "Dogs are cool",
"description" : "I like huskies",
"image" : "https://media1.giphy.com/media/EvRj5lfd8ctUY/giphy.gif",
"original_poster" : {
"id" : "5a163317bf92864245250cf4",
"username" : "john"
},
"tags" : [
"puppies",
"dogs"
]
}
],
"__v" : 1
}
Yes you can find directly the post title from the user model. like bellow
User.find({"posts.title": "Cats are cool"}, (err, users) => {
if(err) {
// return error
}
return res.send(users)
})
That will return user with all post not only the matching post title. So to return only matching post title can use $ positional operator. like this query
User.find({"posts.title": "Cats are cool"},
{username: 1, "posts.$": 1}, // add that you need to project
(err, users) => {
if(err) {
// return error
}
return res.send(users)
})
that only return matching post
Since you are saving OP data, why not do:
// you'll need to adapt how your are getting the user-id here
const { user } = req
Post.find({ title: 'the title', 'original_poster.id': user.id }, (err, posts) => {
console.log(posts); })
Though I would advise you to adjust your Post-schema:
original_poster: {
type: Schema.Types.ObjectId,
ref: 'User'
}
},
Then you can do Post.find({}).populate('original_poster') to include it in your results.!

Resources