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;
}
);
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?
In my application, I have a post schema (shown below):
const postSchema = new mongoose.Schema({
file: {
type: String,
required: true
},
caption: {
type: String,
maxLength: 2000
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
likeNum: {
type: Number,
default: 0,
min: 0
},
likes: [{
type: mongoose.Schema.Types.ObjectId
}]
})
I want to remove an objectid from the likes array when a user request is sent.
Route:
const post = await Post.findOne({_id: req.params.postid})
const user = req.user._id
post.update({}, {$pull: {likes: user}})
post.likeNum--
await post.save()
res.send('Unliked')
However the objectid is not removed from the array when the route is called. Can anyone spot why? Thanks.
UPDATE:
const user = mongoose.Types.ObjectId(req.user._id)
UPDATE 2:
Post.updateOne({_id: req.params.postid}, { $pull: { likes: mongoose.Types.ObjectId(req.user._id) } })
post.likeNum--
await post.save()
res.send('Unliked')
You can do both operations in a single query no need to findOne,
convert req.user._id to object id using mongoose.Types.ObjectId
$inc to decrees the counts of likeNum
await Post.updateOne(
{ _id: req.params.postid },
{
$pull: { likes: mongoose.Types.ObjectId(req.user._id) },
$inc: { likeNum: -1 }
}
);
res.send('Unliked');
Playground
I have a user schema and each user have a profile in which he has a collection of book, and the user wants to remove a single book from the bookCollection, I have tried my code is at the bottom. The user schema is as follows:
var bookSchema = new Schema({
title: {
type: String,
required: true,
},
author: {
type: String,
required: true,
},
publisher: {
type: String,
default: "not set"
},
desc: {
type: String,
default: "not set"
},
availableAs: {
type: String, //either hardcopy or softcopy
required: true
},
price: {
type: Number,
default: 0
},
category: {
type: String,
default: "not set"
},
imageurl: {
type: String,
default: 'nobook.png'
},
bookurl: {
type: String,
default: ''
},
softcopy_available: {
type: Number,
default: 0
}
});
var userSchema = new Schema({
admin: {
type: Boolean,
default: false
},
bookCollection: [bookSchema]
});
This is what I am trying, but deletion is not working, sometimes it shows error and the page keeps on loading.
router.post('/', (req, res, next) => {
console.log(req.body.bookid);
var id=req.body.bookid;
users.findOne({
})
.then((user1) =>
user1.bookCollection.pull(req.body.bookid._id);
})
.catch((err) => {
next(err)
});
});
Why don't you use updateOne, or UpdateMany to pull the book from bookcollection, if you need to remove from a single user
var ObjectId = mongoose.Types.ObjectId;
users.updateOne({_id: ObjectId(user_id)},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});
If want to remove a certain book from all the users
var ObjectId = mongoose.Types.ObjectId;
users.updateMany({},{ $pull: { bookCollection: { _id: ObjectId(req.body.bookid._id) } }})
.then((results) =>
// results of your update query
})
.catch((err) => {
next(err)
});
I have a little question. I have a User schema which contains a table fields redirecting to the Table schema.
A Table element can contain a name, I want this name to be unique per User but not between User.
Example:
User1 -> Table1.name: "foo"
User2 -> Table1.name: "foo"
But this User1 -> Table2.name: "foo" cannot be possible.
This is the User Schema:
var UserSchema = new mongoose.Schema({
username: { type: String, required: true, index: {
unique: true } },
email: { type: String, required: true, index: {unique: true } },
password: { type: String, required: true },
tables: [{ type: Schema.Types.ObjectId, ref: 'Table' }],
resetPasswordToken: String,
resetPasswordExpires: Date,
uuid: String,
});
This is the Table schema:
var TableSchema = Schema({
name: { type: String, required: true, index: { unique: true }},
logos: [{ type: Schema.Types.ObjectId, ref: 'Logo'}],
});
And this is where I do the queries:
app.post('/newTab', function(req, res){
var use = req.user.username;
var newTab = new Table({
name: req.body.name,
});
newTab.save(function(err, docs){
if (err)
{
console.error(err);
res.writeHead(500);
res.end();
}
else
{
User.findOne({username: req.user.username}, function(err, docs) {
if(err) {throw (err);}
else
{
docs.tables.push(newTab);
docs.save(function(err, docs){
if (err) return console.error(err);
res.writeHead(200);
res.end(userId);
});
}
});
}
});
For now, I cannot add the same table name for two different User ..
I also tried something with sparse index but can't figure how it works
I am trying to populate my users car inventory. All the cars have a userId attached to them when they are created but when I go to populate the inventory it doesn't work and I get no errors.
Here are my models:
User.js
let UserSchema = mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
inventory: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Car' }]
});
let User = mongoose.model('User', UserSchema);
models.User = User;
Cars.js
let CarSchema = mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
make: {
type: String,
required: true
},
model: {
type: String,
required: true
},
year: {
type: String
}
});
let Car = mongoose.model('Car', CarSchema);
models.Car = Car;
Here is the populate code:
router.route('/users/:user/inventory').get((req, res) => {
User.findById(userId)
.populate('inventory')
.exec((err, user) => {
if (err) {
console.log("ERRROORRR " + err)
return res.send(err);
}
console.log('Populate ' + user)
res.status(200).json({message: 'Returned User', data: user});
});
});
};
This is what a car object looks like in the database:
{
"_id": ObjectId("5759c00d9928cb581b5424d0"),
"make": "dasda",
"model": "dafsd",
"year": "asdfa",
"userId": ObjectId("575848d8d11e03f611b812cf"),
"__v": 0
}
Any advice would be great! Thanks!
Populate in Mongoose currently only works with _id's, though there's a long-standing issue to change this. You'll need to make sure your Car model has an _id field and that the inventory field in User is an array of these _id's.
let CarSchema = new mongoose.Schema(); //implicit _id field - created by mongo
// Car { _id: 'somerandomstring' }
let UserSchema = new mongoose.Schema({
inventory: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Car'
}]
});
// User { inventory: ['somerandomstring'] }
User.populate('inventory')