I cannot remove a subdocment in mongo Db? - mongodb

I am trying to delete a subdocument from my users collection in Mongo Db, my best attempt to remove the subdocument is the the route below. However is does not work. I have been able to $unset the entire Favorite Movies array but I only want to delete one Item by its _id within the Favorite Movies Sub-Document. What am I doing Wrong.
// My Route That is supposed to Delete a Subdocument:
app.put('/Favorites/:UserName/delete/:_id',passport.authenticate('jwt', { session: false }), (req, res) => {
users.findOneAndUpdate({ UserName: req.params.UserName })
.then((user) => {
if (!user) {
res.status(400).send('ID: ' + req.params._id + ' was not found!!');
} else {
user.updateOne(
{UserName: req.params.UserName},
{
$pull: {
"FavoriteMovies": {
"ObjectId": req.params._id
}
}
})
res.status(200).send('ID: ' + req.params._id + ' was deleted!');
}
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
//Mongoose Model Schema for User in which the Subdocuemnt I want to delete is in Favorite Movies:
let usersSchema = mongoose.Schema({
_id: {type: Object},
UserName: {type: String, required: true},
Password: {type: String, required: true},
Email: {type: String, required: true},
Birthday: Date,
FavoriteMovies:{type: Object},
ImagePath: String
});
The User Object with Favorite Movies Subdocument in Postman- Raw:
[
{
"_id": 1650119097711,
"UserName": "robbies",
"Password": "$2b$10$UZmRBLZF0UGWrB1OrZVI2ePc7N1ae5sSZj0RlSU8WyRIRsfdE.yYW",
"Email": "rob#gmail.com",
"Birthday": "1988-05-05T00:00:00.000Z",
"FavoriteMovies": [
{
"ObjectId": 2009,
"Title": "The NoteBook",
"Genre": "Romance"
},
{
"ObjectId": 2001,
"Title": "Hacksaw Ridge",
"Genre": "Action"
}
],
"ImagePath": null,
"__v": 0
}
]

Related

how to populate reference field when that document is updated

I have 2 collections Users and Bookings. I created userSchema and bookingSchema and routes of bookings and users.
User Schema
const userSchema = new mongoose.Schema({
name: String,
active: {
type: Boolean,
default: true,
// select: false,
},
});
userSchema.pre(/^find/, function (next) {
this.find({ active: { $ne: false } });
next();
});
Booking Schema
const bookingSchema = new mongoose.Schema({
from: String,
to: String,
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
},
});
bookingSchema.pre(/^find/, function (next) {
this.populate({
path: 'user ',
});
next();
});
I defined my routes as follows
router.get('/api/bookings/:id', async (req, res) => {
const booking = await Booking.findById(req.params.id);
res.send(booking);
});
My issue is I created user document
{
_id: "60ab239958c0ac2882d30531",
active: true,
name: "rohit"
}
and booking document
{
"_id": "60ab1fe50618d805581f154a",
"from": "delhi",
"to": "mumbai",
"user": {
"_id": "60ab1fac0618d805581f1549",
"name": "rohit",
"__v": 0
},
"__v": 0
}
Now when I update active field to false in user "rohit" then when I fetch booking of rohit I get null in user field! (I can't delete pre middleware in user schema)
{
"_id": "60ab1fe50618d805581f154a",
"from": "delhi",
"to": "mumbai",
"user": null,
"__v": 0
}

Mongoose $push add to document

I'm trying to add an element to an existing array, but it produces an error:
The field 'data' must be an array but is of type object in document
Scheme:
const testScheme = new Schema({
user: {
type: String,
required: true
},
data: [{
platform: {
type: String,
required: true
},
item_name: {
type: String,
required: true
},
price: {
type: Number,
default: 0
},
updatedAt: Date
}]
}, {
versionKey: false,
timestamps: true
});
Document in mongodb:
"data": [{
"price": 50,
"_id": "5a84268d6c78a60c10479437",
"platform": "pl1",
"item_name": "test"
}],
"_id": "5a841bccb44cb8cd5b974d71",
"user": "Ivan",
"updatedAt": "2018-02-14T12:07:41.793Z",
"createdAt": "2018-02-14T11:21:48.104Z"
Query:
var item = {
"platform": "pl700",
"item_name": "someText",
"price": 700,
"updatedAt": new Date()
};
Data.findOneAndUpdate({
'user': 'Ivan'
}, {
$push: {
'data': item
}
}, {
safe: true,
upsert: true
},
function(err, data) {
if (err) return res.status(500).send({
'error': err
});
res.status(200).send({
'data': data
});
}
);
I trying query with $set parametr and it works, but $push, $addToSet didn't work for me. Also i tried to google this problem and can't solve it.
It is not clear what you are intending to do.
To push an item into array you use $addToSet/$push. For updating a array you use $set.
Using $set you can update the whole document or you can update the specific field.
Update whole doc
Data.findOneAndUpdate({
'user': 'Ivan',
'data._id':item._id
}, {
$set: {
'data.$': item
}
}...
)
Update specific field
Data.findOneAndUpdate({
'user': 'Ivan',
'data._id':item._id
}, {
$set: {
'data.$.price': item.price
}
}...
)

How to populate multilevel array in mongoose

I have a Quiz Model with array of Section and each Sections has array of reference to Question.
I want to populate Quiz with question.
QuizModel
var quizSchema = new Schema({
name: String,
code: Number,
creator: String,
createdBy: { type: Schema.Types.ObjectId, ref: 'user' },
section:[{
title: String,
questions: [{type: Schema.Types.ObjectId ,ref: 'question'}]
}],
createdOn: {type:Date, default:Date.now}
});
and questionModel
var questionSchema = new mongoose.Schema(
{
question: String,
answer: [String],
correct: Number,
createdOn: {type:Date, default:Date.now}
});
I have following the official mongoose documentation for populating
http://mongoosejs.com/docs/populate.html#deep-populate
My attempt
quizSchema.find({_id: quiz_id})
.populate({
path: 'section' ,
populate: {
path: 'section.questions',
model: 'questionSchema'
}
})
.exec( function (err, result) {
if (err) return done(err,null);
console.log("list of questions are" + result);
return done(err, result);
});
}
The output I am getting is list of question's id not the actual question.
{
"status": "success",
"message": "Quiz data",
"result": [
{
"_id": "57fd5912ec0ad6bc8b67d71c",
"name": "My Quiz",
"creator": "foo",
"__v": 0,
"code": 124,
"createdOn": "2016-10-11T21:26:42.774Z",
"section": [
{
"_id": "57fd7e82c20a2fe5da3ed569",
"questions": [
"57fd7f8560e98fe710878820",
"57fd7f9d60e98fe710878821",
"57fd81408b20dae9108d347c",
"57fd81408b20dae9108d347d",
"57fd826aea5159ea5ff2f1a9",
"57fd82ab0dbc0feaa753e50c",
"57fd82efd789afeb0353f036",
"57fd84b0fef6a2ed21fad5ae",
"57fd84cc5dab10ed471bcaf5",
"57fd84cd5dab10ed471bcaf6"
]
},
{
"title": "next section",
"_id": "57fff1e0f1913138c27e50a0",
"questions": [
"57fff242f1913138c27e50a1"
]
}
]
}
]
}
I think I am doing something wrong with populate field, but not sure .
Just alter your query to
quizSchema.find({_id: quiz_id})
.populate({
path: 'section.questions'
})

Populating array in mogo

I have created the following Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Player = require('./player');
var gameSchema = new Schema({
created_at: Date,
nrOfCards: String,
players: [{
sticks: String,
player: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Player'
}
}],
});
var Game = mongoose.model('Game', gameSchema);
The saving part works fine and a saved object may look something like this:
"_id": "57dd11aca0c36114588fd250",
"nrOfCards": "3",
"__v": 0,
"players": [
{
"_id": "57d415e527c20f3ed2416e05",
"age": "33"
},
{
"_id": "57d417df2186d53f3d49c996",
"age": "73"
},
{
"_id": "57d41d85ec315d4234010c7d",
"age": "20"
}
]
},
After having saved an object I would like to have it returned with the player-field populated. Here is my attempt:
app.post('/api/games', function(req, res) {
Game.create({
players : req.body.activePlayers,
nrOfCards: req.body.nrOfCards,
}, function(err, game) {
if (err) {
res.send(err);
} else {
Game.findOne(game)
.populate('players.player')
.exec(function (err, newgame) {
if (err) return handleError(err);
console.log(newgame);
res.json(newgame);
});
}
});
});
Thinking that the .populate('players.player') should do the trick , but I'm receiving the unpopulated field containing the _id of player only.
Tips appreciated. Thanks!
Use
player: {
type: Schema.Types.ObjectId,
ref: 'Player'
}
into your schema.

Mongoose not populating previously saved document with reference to newly saved document

all.
I am writing a MEAN stack application, using Mongoose (4.0.6) with Node/Express to interface with MongoDB, and I am running into difficulty populating saved documents when I later save new documents that the existing document should have a reference to. Specifically, in the app I have a user create an instance of a company before creating their admin account for that company, so when the user registers him/herself as an admin, I'd like the company document to populate its users array with the new user.
Here are my schemas for company and user:
User.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var userSchema = new Schema({
first_name: { type: String, required: '{PATH} is required!' },
last_name: { type: String, required: '{PATH} is required!' },
username: { type: String, required: '{PATH} is required!', lowercase: true, unique: true },
password: { type: String, required: '{PATH} is required!' },
roles: { type: [String] },
company: { type: ObjectId, ref: 'Company', required: true },
db_permissions: [{ type: ObjectId, ref: 'DataConnection' }],
created_by: { type: ObjectId, ref: 'User' },
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
};
Company.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var companySchema = new Schema({
name: { type: String, uppercase: true, required: '{PATH} is required!', unique: true },
industry: { type: String, required: '{PATH} is required!' },
phone: { type: String, required: '{PATH} is required!' },
address_line_1: { type: String, uppercase: true, required: '{PATH} is required!' },
address_line_2: { type: String, uppercase: true },
city: { type: String, uppercase: true, required: '{PATH} is required!' },
state_prov: { type: String, uppercase: true, required: '{PATH} is required!' },
postal_code: { type: String, required: '{PATH} is required!' },
country: { type: String, required: '{PATH} is required!' },
logo_url: String,
users: [{ type: ObjectId, ref: 'User' }],
data_connections: [{ type: ObjectId, ref: 'DataConnection' }],
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var Company = mongoose.model('Company', companySchema);
module.exports = {
Company: Company
};
Here is the code in my controller:
User.create(userData, function(err, user) {
if(err) {
if(err.toString().indexOf('E11000') > -1) {
err = new Error('Duplicate email');
}
res.status(400);
return res.send({ reason:err.toString() });
}
console.log('company id: ' + user.company);
Company.findById(user.company)
.populate({path: 'users'})
.exec(function (err, company) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
res.send(user);
The company (e.g. TEST53) saves to the database correctly with an empty users array:
{
"_id": "55ae421bf469f1b97bb52d5a",
"name": "TEST53",
"industry": "Construction",
"phone": "2352626254",
"city": "GDFGD",
"country": "United States",
"address_line_1": "DSGDFGH",
"state_prov": "GF",
"postal_code": "45645",
"logo_url": "",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:07.609Z"
],
"created_at": "2015-07-21T12:59:07.597Z",
"data_connections": [],
"users": []
}
Then when I create the user, it saves correctly:
{
"_id": "55ae4238f469f1b97bb52d5b",
"username": "test53#test.com",
"password": "$2a$12$ZB6L1NCZEhLfjs99yUUNNOQEknyQmX6nP2BxBvo1uZGlvk9LlKGFu",
"company": "55ae421bf469f1b97bb52d5a",
"first_name": "Test53",
"last_name": "Admin",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:36.925Z"
],
"created_at": "2015-07-21T12:59:36.550Z",
"db_permissions": [],
"roles": [
"admin"
]
}
And I can see that the correct ObjectId prints to the console for user.company:
company id: 55ae421bf469f1b97bb52d5a
But the company's users array doesn't populate with the user's id, and the console.log inside the .exec function prints 'TEST53's users now includes '.
I have tried several ways of wiring this up, with just 'users' instead of { path: 'users' }, writing a function that pushes the user into the array, using .run instead of .exec, but so far without success.
Is there something obvious I'm missing? Thanks in advance for any suggestions!
You're not actually adding the user to the company.
Try this:
Company.findById(user.company, function (err, company) {
if (err) return handleError(err);
// Add the user to the company's list of users.
company.users.push(user);
// Need to save again.
company.save(function(err) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
});
res.send(user);
It seems to me that all you want to do is to update the Company model to add the user, as opposed to actually use the (populated) Company document as a response, so I left out an additional Company.findById(...).populate(...) call.