Take a look at the following schema design:
var message = new Schema({
receivers: [User],
message: String,
owner: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
var user = new Schema({
name: String,
photo: String
});
var inbox = new Schema({
messages: [Message],
owner: {
type: Schema.Types.ObjectId,
required: true
},
sequence: Number
});
When I try to create a new message with:
var newMessage = {
receivers: ['<id1>', '<id2>'],
message: 'Hello world',
owner: '<userId>'
}
Inbox.findOneAndUpdate({
owner: '<userId>'
}, {
$push: {
messages: newMessage
},
$set: {
sequence: '<sequence>'
}
}, {
upsert: true
}, callback);
It returns the following error:
MongooseError.CastError "Cast to undefined failed for value [object Object] at path "messages""
What am I doing wrong? How can I make it work?
Thanks.
The receivers field for the message object is expecting an array of objects with the User schema, not an array of ObjectId's hexadecimal string representation. Thus you need to replace the receivers array with the actual objects represented by the ids, something like
var newMessage = {
receivers: ['<id1>', '<id2>'],
message: 'Hello world',
owner: '<userId>'
};
Users.find({ "_id": {"$in": newMessage.receivers} }, function (err, users){
// handle error
if (err) throw err;
// do the update
newMessage.receivers = users;
Inbox.findOneAndUpdate(
{ owner: '<userId>'},
{
$push: { messages: newMessage },
$set: { sequence: '<sequence>' }
},
{ upsert: true}, callback
);
});
Related
I'm trying to filter my pets by category, I have the following model of pets:
const Pet = mongoose.model(
'Pet',
new Schema({
name: {
type: String,
required: true,
},
age: {
type: Number,
required: true,
},
description: {
type: String,
},
weight: {
type: Number,
required: true,
},
color: {
type: String,
required: true,
},
images: {
type: Array,
required: true,
},
available: {
type: Boolean,
},
category: Object,
user: Object,
adopter: Object,
}, { timestamps: true }),
);
module.exports = Pet;
when I try to get the data through postman it returns an empty array as a response.
my code to filter by category:
static async getByCategory(req, res) {
const id = req.params.id;
// check if id is valid
if (!ObjectId.isValid(id)) {
res.status(422).json({ msg: 'Invalid ID' });
return;
}
const pets = await Pet.find({ 'category._id': id }).sort('-createdAt');
if (!pets) {
res.status(404).json({ msg: 'Pets not found!' });
return;
}
res.status(200).json({ pets });
}
it's my first time using mongodb so i'm not sure what's wrong.
id being passed from the client side is string and the one which is saved in the db is ObjectId. Convert the string to Mongoose ObjectId before Pet.find().
const id = mongoose.Types.ObjectId(req.params.id);
const pets = await Pet.find({ 'category._id': id }).sort('-createdAt');
Don't forget to import 'mongoose'.
Could you check that your MongoDB indeed has a field category._id?
I have this in my backend:
ad = await Ad.find({'company': companyId}).populate('creator');
And when i console.log(ad) i get this:
[
{
connections: [],
status: 1,
_id: 6047c711b1f8cf1c98b2227c,
title: "DOTA: Dragon's Blood | Teaser | Netflix",
company: 6047c6fab1f8cf1c98b2227a,
video: 'uploads\\videos\\7802d640-810a-11eb-83c2-57e23ae6d491.mp4',
creator: {
companies: [Array],
ads: [Array],
_id: 6047c6e7b1f8cf1c98b22279,
name: 'test test',
email: 'test#live.com',
image: 'uploads\\images\\5f3ea850-810a-11eb-83c2-57e23ae6d491.jpeg',
password: '',
__v: 3
},
__v: 0
},
{
connections: [ 6047c745b1f8cf1c98b22280, 6047c83bb1f8cf1c98b22286 ],
status: 1,
_id: 6047c72cb1f8cf1c98b2227f,
title: 'Diretide 2020',
company: 6047c6fab1f8cf1c98b2227a,
video: 'uploads\\videos\\87a97d60-810a-11eb-83c2-57e23ae6d491.mp4',
creator: {
companies: [Array],
ads: [Array],
_id: 6047c6e7b1f8cf1c98b22279,
name: 'test test',
email: 'test#live.com',
image: 'uploads\\images\\5f3ea850-810a-11eb-83c2-57e23ae6d491.jpeg',
password: '',
__v: 3
},
__v: 6
}
]
But when i try to console.log(ad.creator) or console.log(ad.creator.ads) im getting undefined error.. I need this becasue i want to pull some things from ad.creator.ads..
Do i miss something in my code?
I will try to be more specific i tried but i cant figure how to do this:
ad.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const adSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
video: { type: String, required: true },
company: { type: mongoose.Types.ObjectId, required: true, ref: 'Company' },
creator: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
connections: [{type: mongoose.Schema.ObjectId, ref: 'User'}],
status: {type: Number, default: '1'}
});
module.exports = mongoose.model('Ad', adSchema);
So i need here when i delete this company to also pull all companies from user..
This is user.js
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, minlength: 6 },
image: { type: String, required: true },
companies: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Company' }],
ads: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Ad' }]
});
userSchema.plugin(uniqueValidator);
module.exports = mongoose.model('User', userSchema);
process for deleting company in // i specified part with problem where need to pull ads from user for this:
const deleteCompany = async (req, res, next) => {
const companyId = req.params.cid;
let company;
let ad;
try {
company = await Company.findById(companyId).populate('creator');
ad = await Ad.find({'company': companyId}).populate('creator');
} catch (err) {
const error = new HttpError(
'backend_message13',
500
);
return next(error);
}
if (!company) {
const error = new HttpError('backend_message14', 404);
return next(error);
}
if (company.creator.id !== req.userData.userId) {
const error = new HttpError(
'backend_message15',
401
);
return next(error);
}
const imagePath = company.image;
try {
const sess = await mongoose.startSession();
sess.startTransaction();
await company.remove({ session: sess });
company.creator.companies.pull(company);
await company.creator.save({ session: sess });
// here is the path where is problem i also tried with ad[0]
ad.creator.pull(ad.creator.ads);
await ad.creator.save({ session: sess });
//
await Ad.deleteMany({'company': companyId});
await sess.commitTransaction();
} catch (err) {
const error = new HttpError(
err,
500
);
return next(error);
}
fs.unlink(imagePath, err => {
console.log(err);
});
ad.forEach(function (item) {
const videoPath = item.video;
const thumb = item.video.replace("uploads\\videos\\","uploads\\videos\\thumb\\").replace(".mp4", "_screenshot.jpeg");
fs.unlink(videoPath, err => {
console.log(err);
});
fs.unlink(thumb, err => {
console.log(err);
});
});
res.status(200).json({ message: 'backend_message17' });
};
Thanks for help :)
append lean() mean on populate and then see
ad = await Ad.find({'company': companyId}).populate('creator').lean();
The query Ad.find() returns an array - but your code tried to access it as an object:
ad = await Ad.find({'company': companyId}).populate('creator');
console.log(ad.creator)
ad.creator actually is an undefined
Use an index to access required array element:
ad = await Ad.find({'company': companyId}).populate('creator');
console.log(ad[0].creator)
Or switch to Ad.findOne()
I try to check if a value is in array's objects. After that I push the object is the value is not in the array. How can I do this ?
router.post('/save', (req, res) => {
let userId = req.user.id
let dataPushSave = req.body.idSave
let dataPushSaveObj = {idSave: dataPushSave}
User.findById(userId, (err, user) => {
if (user.favorites.idSave !== dataPushSave) {
user.favorites.push(dataPushSaveObj)
user.save()
}
})
My mongoose model:
const User = new Schema({
firstName: {
type: String,
required: true
},
favorites: [{
_id: Object,
idSave: String
}]
});
const User = new Schema({
firstName: {
type: String,
required: true
},
favorites: [{
_id: Object,
idSave: String
}]
});
From the above schema, remove _id: Object from favorites.
I would recommend below schema
const User = new Schema({
firstName: {
type: String,
required: true
},
favorites: {
type: [new Schema({
idSave: { type: String },
}, { _id: false })]
}
});
Then use $addToSet operator to make sure there are no duplicates in the favorites array.
let user;
User.findByIdAndUpdate(
userId,
{ $addToSet: { favorites: dataPushSaveObj } },
{ new: true }, // this option will make sure you get the new updated docc
(err, doc) => {
if (err) console.error(err);
user = doc;
}
);
On calling .map on an array of objects, it's throwing an error of TypeError: friends.map is not a function.
when I do it in vanilla js with the object, it works fine, but that's after I enclose the id and _id values in quotes.
is that the cause as it's of type ObjectId in Mongoose? if so, how do I fix it?
var UserSchema = new Schema({
username : String,
firstName : String,
lastName : String
friends : [{ id: { type: Schema.Types.ObjectId, ref: 'User'}, status: Number }]
});
app.get('/getFriends', requireLogin, function(req, res) {
User.findOne({ _id: req.user.id }, 'friends')
.populate({
path: 'friends.id',
model: 'User',
select: 'username firstName lastName -_id'
})
.exec(function(err, friends) {
console.log(typeof(friends))
console.log(friends)
friends = friends.map(function(v) {
delete(v._id);
delete(v.status);
return v;
});
res.json(friends);
})
})
events.js:163
throw er; // Unhandled 'error' event
^
TypeError: friends.map is not a function
the output of console.log(friends)
[ { _id: 590bbb88858367c9bb07776e,
status: 2,
id: 590bba9c858367c9bb077759 },
{ _id: 590bbb95858367c9bb07776f,
status: 2,
id: 590bbad5858367c9bb07775f },
{ _id: 590bbb9e858367c9bb077770,
status: 2,
id: 590bbb05858367c9bb077765 },
{ _id: 590bbbaa858367c9bb077771,
status: 2,
id: 590bbaf2858367c9bb077763 },
{ _id: 590bbbb6858367c9bb077772,
status: 2,
id: 590bbae5858367c9bb077761 },
{ _id: 590bbbc5858367c9bb077773,
status: 2,
id: 590bbabe858367c9bb07775d },
{ _id: 590bbbef858367c9bb077774,
status: 2,
id: 590bbab2858367c9bb07775b } ]
In your code, you are calling .findOne on the User model to query for a document with the _id in the params.
.findOne returns a single mongoose document (Not an array), so the second argument in the callback for exec should refer to the user with with that _id, with only a populated friends property. I don't quite see how you would be getting the logged output you provided. Try something along these lines:
app.get('/getFriends', requireLogin, function(req, res) {
User.findOne({ _id: req.user.id }, 'friends')
.populate({
path: 'friends.id',
model: 'User',
select: 'username firstName lastName -_id'
})
.exec(function(err, user) {
var friends = user.friends.map(function(v) {
delete(v._id);
delete(v.status);
return v;
});
res.json(friends);
})
})
The following piece of code which works fine. However,when I run it again from my cmd(node server),I get a duplicate key message of the dish name. I have two files. The dishes.js where I define my schemas and make available to my second file called server.js.
dishes
// grab the things we need
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var commentSchema = new Schema({
rating: {
type: Number,
min: 1,
max: 5,
required: true
},
comment: {
type: String,
required: true
},
author: {
type: String,
required: true
}
}, {
timestamps: true
});
// create a schema
var dishSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true
},
comments:[commentSchema]
},
{
timestamps: true
});
// the schema is useless so far
// we need to create a model using it
var Dishes = mongoose.model('Dish', dishSchema);
// make this available to our Node applications
module.exports = Dishes;
and my server.js file.
var mongoose = require('mongoose'),
assert = require('assert');
var Dishes = require('./models/dishes-3');
// Connection URL
var url = 'mongodb://localhost:27017/conFusion';mongoose.connect(url);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
// we're connected!
console.log("Connected correctly to server");
// create a new dish
Dishes.create({
name: 'Uthapizza',
description: 'Test',
comments: [
{
rating: 3,
comment: 'This is insane',
author: 'Matt Daemon'
}
]
}, function (err, dish) {
if (err) throw err;
console.log('Dish created!');
console.log(dish);
var id = dish._id;
// get all the dishes
setTimeout(function () {
Dishes.findByIdAndUpdate(id, {
$set: {
description: 'Updated Test'
}
}, {
new: true
})
.exec(function (err, dish) {
if (err) throw err;
console.log('Updated Dish!');
console.log(dish);
dish.comments.push({
rating: 5,
comment: 'I\'m getting a sinking feeling!',
author: 'Leonardo di Carpaccio'
});
dish.save(function (err, dish) {
console.log('Updated Comments!');
console.log(dish);
db.collection('dishes').drop(function () {
db.close();
});
});
});
}, 3000);
});
});
If you pay a close attention in the server.js file I have removed the unique: true attribute from by dishes.js file,but I still have the same problem.
name: {
type: String,
required: true,
unique: true
},
when your schema is given below
name: {
type: String,
required: true,
unique: true
}
the unique is working
when your schema is given below
name: {
type: String,
required: true
}
the unique not working
after change your schema definition, drop all your collection and try to insert.