Hey I was wondering how do I use findById for a schema inside an array? For example, I have the following Schema:
const GameSchema = new mongoose.Schema({
users: [
{
user: { type: mongoose.Schema.ObjectId, ref: 'User' },
role: {
type: String,
required: true,
enum: ['user', 'moderator', 'creator'],
default: 'user',
},
},
]
}]
I want to find the user with a mongoose function like findById, such as the following:
const user = await game.users.findById({ user: req.user.id })
It doesn't seem to work since users is not a mongodb model. I know I can find the user by using find() like the following:
const user = await game.users.find(
(gameUser) => gameUser.user == req.user.id
)
The only problem is that the type of gameUser and req.user.id is not the same and I can't use '==='. Is there some way to go through the array and use the mongoose function findById?
As docs explains, findById method:
Finds a single document by its _id field
So you have to use findOne() instead of findById().
Also, to return only one field from the entire array you can use projection into find.
Check this example. This query find an object by its id (i.e. user field) and return only the object, not the whole array.
db.collection.find({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})
Using mongoose you can do:
yourModel.findOne(({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})).then(result => {
console.log(result)
}).catch(e => {
// error
})
Related
I have the following schema which contains a property with an array:
const projectSchema = new mongoose.Schema(
{
title: {
type: String,
required: [true, "Please add a title"],
},
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
},
);
In my project controller, I'm trying to add users to this array without getting a duplicate user. So I use $addToSet. It works fine but it doesn't return an error when there is a duplicate user.
const project = await Project.findOneAndUpdate(
{ _id: id },
{ $addToSet: { users: userID } },
{ new: true }
);
How can I detect that it didn't add a user (because the user already exists in the array) and return an error?
I try to remove an element from an array attribute of my object.
This is my schema :
const userSchema = new mongoose.Schema({
userID: {
type: Number
},
name: {
type: String
},
names: [
{
text: { type: String, required: true },
order: {
type: Number,
required: true
}
}
]
});
this is my mongoose function :
User.findOne({ userID: Number(req.params.id) })
.then((user) => {
user.names.remove({text: "john", order: 3});
recipe.save(() => {
res.json(recipe);
});
})
I don't understand why it's not good :/
As per documentation of mongoose remove method remove operation is only executed when a callback is passed. To force execution without a callback, you must first call remove() and then execute it by using the exec() method.
Since you are trying to delete from array of objects then better would be to use pull operator. You don't have to do find and remove, you can simply use update method.
As per documentation of $pull operator you can either specify a value or a condition
i.e.
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your scenario you need to either specify complete value of one or more names item object or an condition that matches one or more names item
Add the condition where you match id of names item or if you don't know that then you can use elemMatch to match on few fields i.e.
Use following pull condition to solve the issue:
User.update(
{ _id: Number(req.params.id) },
{ $pull: { 'names': { $elemMatch: { 'text': "john", 'order': 3 }} } },
(error, success) => {
if (error) console.log(error);
console.log(success);
}
);
To Remove Element from array in document please follow as below
User.update(
{
userID: Number(req.params.id),
},
{
$pull: { names: { $elemMatch: { text: "john", order: 3 } } }
},
{
multi: false
}
).lean().then((Status) => {
console.log("Status-->", Status);
res.json('Removed Successfully');
})
Refer $pull operator at link
I'm trying to update an array in document by adding object if it doesn't exist, and replacing the object in array otherwise. But nothing ($push, $addToSet) except the $set parameter does anything, and $set works as expected - overwrites the whole array.
My mongoose schema:
var cartSchema = mongoose.Schema({
mail: String,
items: Array
});
The post request handler:
app.post('/addToCart', function(req, res) {
var request = req.body;
Cart.findOneAndUpdate({
"mail": request.mail
}, {
$addToSet: {
"items": request.item
}
}, {
upsert: true
},
function(err, result) {
console.log(result);
}
);
res.send(true);
});
The data that I'm sending from the client:
{
"mail":"test#gmail.com",
"item":{
"_id":"59da78db7e9e0433280578ec",
"manufacturer":"Schecter",
"referenceNo":"Daemon-412",
"type":"Gitare",
"image":"images/ba9727909d6c3c26412341907e7e12041507489988265.jpeg",
"__v":0,
"subcategories":[
"Elektricne"
]
}
}
EDIT:
I also get this log when I trigger 'addToCart' request:
{ MongoError: The field 'items' must be an array but is of type object in
document {_id: ObjectId('5a19ae2884d236048c8c91e2')}
The comparison in $addToSet would succeeded only if the existing document has the exact same fields and values, and the fields are in the same order. Otherwise the operator will fail.
So in your case, request.item always need to be exactly the same.
I would recommend creating a model of "item". Then, your cart schema would be like:
var cartSchema = mongoose.Schema({
mail: String,
items: [{
type: ObjectId,
ref: 'item',
}],
});
And let MongoDB determine if the item exist.
this should work you just need to implement objectExits function that test if the item is that one you're looking for :
Cart.findOne({ "mail": request.mail })
.exec()
.then(cart => {
var replaced = cart.items.some((item, i) => {
if (item._id == request.item._id)) {
cart.items[i] = request.item;
return true;
}
})
if (!replaced) {
cart.items.push(request.item);
}
cart.save();
return cart;
})
.catch(err => {
console.log(err)
});
I know how to add object to collection in MongoDB using Node.js, for example:
router.post('/addProduct', function (req, res) {
Partner.findByIdAndUpdate({ _id: req.body.partnerId }, { $push: { "products": { name: req.body.dataProduct.name } } }, { safe: true }, function (err, response) {
if (err) throw err;
res.json(response);
});
});
but what if in product will be another table? How can I simply add object there?
Let's say this is my schema:
var partnerSchema = new mongoose.Schema({
name: String,
products: [
{
name: String,
campaignList: [
{
name: String,
type: String,
startDate: Date,
endDate: Date,
paymentMethod: String,
partnerPayout: Number,
ourPayout: Number
}
]
}]
});
ID in each partner and product are default ._id eg. partner._id and product._id. That's why aren't in schema above. However I sending them from FrontEnd to BackEnd as a req.parameter - normally thing but i wanted to say it for sure :)
Your best bet would bet to define the Schema & Model for the campaign on its own, and add it to the Partner by reference using the _id
var partnerSchema = new mongoose.Schema({
name: String,
products: [
{
name: String,
campaignList: [
{ type : mongoose.Schema.Types.ObjectId, ref : 'campaignModel' }
]
}]
});
var campaignSchema = new mongoose.Schema({
name: String,
type: String,
startDate: Date,
endDate: Date,
paymentMethod: String,
partnerPayout: Number,
ourPayout: Number
});
var campaignModel = mongoose.model('campaignModel', campaignSchema);
var partnerModel = mongoose.model('partnerSchema', partnerSchema);
A good practice is to look for times where you're trying nest semi-complex data, or objects with more than two or three keys, and extract them into their own collection. Not only does it make it easier to search for those documents, it makes it easier to use them in conjunction with other objects.
Be sure to call .populate() during your query so that MongoDB knows to nest the documents from the other collections, otherwise, you'll just have an array of ObjectId.
First match the required products array position. You can confirm this by testing a simple find like:
Partner.find({_id: req.body.partnerId), 'products.name': req.body.dataProduct.name }, { 'products.$': 1})
Use the positional $ operator to push the new object into the array in the matched product element:
Partner.update({_id: req.body.partnerId), 'products.name': req.body.dataProduct.name }, { $push: { 'products.$.campaignList': { name: 'new campaign' }}})
Reference https://docs.mongodb.com/manual/reference/operator/update/positional/
try this:
router.post('/addProduct', function (req, res) {
Partner.findOneAndUpdate({ _id: req.body.partnerId }, { $push: { "products": { name: req.body.dataProduct.name, $push: {"campaignList": {name: req.body.name}} } } }, { safe: true }, function (err, response) {
if (err) throw err;
res.json(response);
});
});
i hope it helps you
I have this little schema for users:
{
username: String,
contacts: Array
}
So for example some user's contacts will look like this:
{
username: "user",
contacts: [{'id': ObjectId('525.....etc'), 'approved': false}, {'id':ObjectId('534.....etc'), 'approved': true}]
}
Now I need to delete an item from contacts so I do:
model.findByIdAndUpdate(23, {'$pull': {
'contacts':{'id':'525.....etc'}
}});
but seems not working, no errors but it doesn't gets deleted, I just would like to return this document for the user:
{
username: "user",
contacts: [{'id':ObjectId('534.....etc'), 'approved': false}]
}
how to achieve this?
The $pull operator actually just performs the conditions on the array element on which it is operating. It seems that your question might not actually show that you are probably working with an ObjectId value that mongoose creates by default for all array fields.
So you could to your query like this, after importing the ObjectId creation method:
model.findByIdAndUpdate(23, {
'$pull': {
'contacts':{ '_id': new ObjectId(someStringValue) }
}
});
Or in fact you can actually define your "schema" a little better, and mongoose will actually "autocast" the ObjectId for you based on the "type" defined in the schema:
var contactSchema = new Schema({
approved: Boolean
});
var userSchema = new Schema({
username: String,
contacts: [contactSchema]
});
This allows mongoose to "follow the rules" for strictly typed field definitions. So now it knows that you actually have an _id field for each element of the contacts array, and the "type" of that field is actually an ObjectId so it will automatically re-cast "String" values supplied as a true ObjectId.
finaly!
MongoDB:
"imgs" : {"other" : [ {
"crop" : "../uploads/584251f58148e3150fa5c1a7/photo_2016-11-09_21-38-55.jpg",
"origin" : "../uploads/584251f58148e3150fa5c1a7/o-photo_2016-11-09_21-38-55.jpg",
"_id" : ObjectId("58433bdcf75adf27cb1e8608")
}
]
},
router.get('/obj/:id', function(req, res) {
var id = req.params.id;
Model.findOne({'imgs.other._id': id}, function (err, result) {
result.imgs.other.id(id).remove();
result.save();
});