In mongo, I made history column array for each user to get the Id of specific card, so I would like to made a condition or not for knowing that :
To understand my code :
find the ID user, find his history :
if card ID already present => don't duplicate ID on this array
but, if is not present :
add the ID on his own history array.
My req.body._id is the Id value who the user submit
const forThisUser = { _id: req.user._id }
const condition = await User.find(forThisUser, {"history" : { $in : req.body._id}})
async function alreadyPresentOrNot(res, req){
if(condition>0){
console.log("Already present !")
res.sendStatus(401);
}
else{
console.log("Card not finding, add on array now !")
await User.findOneAndUpdate(forThisUser, { $addToSet: { history: req.body._id } }, {upsert: true})
res.sendStatus(201);
}
}
I got this error :
ERROR Expression $in takes exactly 2 arguments. 1 were passed in.
Thanks
Just try using it in an array.
const ids = [req.body._id];
const condition = await User.find(forThisUser, {"history" : { $in : [ids]}})
Here is the official link that says you have to use $in : [array]
https://mongoosejs.com/docs/api/aggregate.html?
Please refer to Monngoose's documentation:
Your query should be:
const forThisUser = { _id: req.user._id }
const condition = await User.find({...forThisUser, "history" : { $in : req.body._id}})
Find takes the filters argument as an object, which would be:
{
_id: req.user._id,
history: { $in: req.body._id }
}
Unrelated to your question, but you may want to have a look at your HTTP response codes as well.
For example, for a duplicated entry you would return a 409 Conflict, or a 400 Bad Request not a 401 Unauthorized.
And if the card is added you can return 200 Success or 204 No Conntent, unless you are creating the card resource in that same request your return 201 Created
Related
In user schema, Location is an array of objects with locations._id is ObjectId.
This is my user service file.
const updatedBy = {
_id: mongoose.Types.ObjectId(req.params.id),
"locations._id": { $in: req.body.locationIds },
};
const updatingData = { $set: { "locations.$.status": req.query.status }};
const user = await userDbServices.updateRecords(updatedBy, updatingData);
In req.body.locationIds, I'm passing an array.
And this one is the user DB service file
exports.updateRecords = async function (updateParam, updatingData) {
return userModel.updateMany(updateParam, updatingData);
};
When I hit the API, The first embedded document of location is updated. But the other ones aren't. How can I solve this?
This is actually the expected behavior of the $ identifier, from the docs:
the positional $ operator acts as a placeholder for the first element that matches the query document
To update multiple elements you want to be using the $[] identifier with arrayFilters, like so:
userModel.updateMany({
_id: mongoose.Types.ObjectId(req.params.id),
"locations._id": { $in: req.body.locationIds },
},
{
$set: {
"locations.$[elem].status": req.query.status
}
},
{
arrayFilters: [
{
"elem._id": {
$in: req.body.locationIds
}
}
]
})
Mongo Playground
I'm creating subdocuments in my event model under guests that look like below. I would like to console.log the corresponding subdoc Id as each guest id is created.
{
"guests" : [
{ "phone" : 11111,
"_id" : ObjectId("61ef629981f154bead6b0de4")
},
{ "phone" : 4444444444,
"_id" : ObjectId("61fca19f95b626e017732139")
}
]
}
I followed the mongoose docs but the code from the docs (below) only logs the first id even as each subsequent doc is created because of the index 0.
// create a comment
parent.children.push({ name: 'Liesl' });
const subdoc = parent.children[0];
console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' }
subdoc.isNew; // true
I tried removing the index 0 and the console log just produces the ever-growing guests array.
module.exports.addGuest = async (req, res) => {
const event = await Event.findById(req.params.id);
const phone = req.body.guest;
event.guests.push(phone);
const guestId = event.guests[0];
console.log(guestId);
await event.save();
res.redirect(`/events/${event._id}`);
}
How do I adjust my function to log the corresponding subdoc Id as it's created?
try applying mongoose hooks on your subschema.
mongoose pre save hook is triggered every time a document is saved in your collection and you can log the id of your document which is being saved.
I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.
I have a problem accessing the _id of the last created element inserted in to mongodbe.
is there any solution to just get the id, instead of getting all elements? especially if the data list is so long and nested so its really hard to pin the created element and gain access to his id
I am using mongoose driver on this one.
let updateDeptArr = await Budget.findOneAndUpdate(
// Dynamic
{
'_id': `${propertyValues[0]}`, // user ID
[`${keys[2]}._id`]: `${propertyValues[1]}`
},
{
'$push': {
[`${keys[2]}.$.${keys[3]}`]: propertyValues[3]
}
}, { _id: true, new: true }
).then(function (data) {
// we need to get and send The id of the last created element!!!
console.log(data[keys[2]]);
// let order = data[keys[1]].length - 1
// let id = data[keys[1]][`${order}`]._id
// res.json({ _id: id })
})
}
You can use select after query.
In the upcoming listing, you have a mongoose schema being used to query MongoDB, and just two fields are selected, as you want.
Loc
.findById(req.params.locationid)
.select('name reviews')//select chained
.exec();
Try to chain select to your call. It will just give back the name and reviews.
Try this:
let updateDeptArr = await Budget.findOneAndUpdate(
// Dynamic
{
'_id': `${propertyValues[0]}`, // user ID
[`${keys[2]}._id`]: `${propertyValues[1]}`
},
{
'$push': {
[`${keys[2]}.$.${keys[3]}`]: propertyValues[3]
}
}, { _id: true, new: true }
).select("_id")// not sure if Mongoose will chain this way
.then(function (data) {
// we need to get and send The id of the last created element!!!
console.log(data[keys[2]]);
// let order = data[keys[1]].length - 1
// let id = data[keys[1]][`${order}`]._id
// res.json({ _id: id })
})
}
I am trying to insert many in mongoDB using mongoose’s .it only save one collection only why
Here is my code
https://codesandbox.io/s/gallant-solomon-o91wp
I save like that
app.get("/saveData", async () => {
try {
const data = [
{
empid: "test123",
date: "19-Jul-2019"
},
{
empid: "test13",
date: "18-Jul-2019"
},
{
empid: "test13",
date: "11-Jul-2019"
}
];
console.log("before save");
let saveBlog = await BlogPostModel.collection.insertMany(data, {
checkKeys: false
}); //when fail its goes to catch
console.log(saveBlog); //when success it print.
console.log("saveBlog save");
} catch (error) {
console.log(error);
}
});
try to fetch data like that
app.get("/filter", async (req, res) => {
try {
let filterBlog = await BlogPostModel.find({});
//when fail its goes to catch
console.log(filterBlog); //when success it print.
res.send(filterBlog);
} catch (error) {
console.log(error);
}
});
showing only one document
So, here as i suspected, there is one more index present in the collection you created i.e blogposts. the index is id [key id name id_1].
Here is your whole project, i have added in glitch.
Demo
and here i also have added one api /indexes , this retrieves all indexes of the collection. by default _id should be there, additional indexes are added after. so here you can see id, which needs to be unique.
i have made few more changes to your code.
The route /saveData now able to insert records. and it has the field called id which is unique.
but, the old route that is now at /saveData_old, which will give you error as there are no keys that represents this index key [id]. [also after inserting one, it will have id null and rest will fail, just causing duplicate ]
now you can either use id key with unique values, or if you don't need you can also drop the index as well. you can find an answer here for how to drop index.