Hi i am new in mongoose and mongodb. I want to remove specific object from the Array in my document and return the updated document. I have tried a lot but it always return null. Here is my document structure.
{
"role": "Student",
"skills": [
"html",
"css",
"js"
],
"_id": "5ef583198e9b23cc8c606c10",
"user": "5ee5c9ef26333935647e54bc",
"__v": 24,
"status": "Intern",
"education": [],
"internships": [
{
"current": false,
"_id": "5ef894d48f601512340f25b5",
"title": "Web",
"company": "asdfadfd",
"from": "2010-02-04T00:00:00.000Z"
},
{
"current": false,
"_id": "5ef894f31dc9413bf89c44d8",
"title": "Django",
"company": "example",
"from": "2010-02-04T00:00:00.000Z"
}
]
}
And here is my updating function
exports.deleteStudentInternship = async (req, res, next) => {
const deleteInternship = await Student.findOneAndUpdate(
{ $and: [{ user: req.user.id }, { 'internships': { $elemMatch: { _id: req.params.intern_id } } }] },
{ '$pull': { 'internships': { _id: req.params.intern_id } } },
{
new: true,
useFindAndModify: false,
},
function (error) {
if (error) return validationError(404, { internship: 'Internship id not exist' }, next)
}
);
if (!deleteInternship) {
return validationError(404, { internship: 'Internship id not exist' }, next)
}
res.status(200).json(deleteInternship);
}
Please change the pull part I mean
{ '$pull': { 'internships': { _id: req.params.intern_id } } }
to this and try:
{ '$pull': { 'internships': req.params.intern_id } }
Related
I am having a response like this
....................................................................................................................................................................................................
{
"data": [
{
"user": "83k13bde05f40640j12075w",
"products": [
{
"type": "shoes",
"amount": 20
},
{
"type": "trousers",
"amount": 6
}
],
"inStock": false
},
{
"user": "9dc3f7de05f40640j12075y",
"products": [
{
"type": "chairs",
"amount": 11
},
{
"type": "bags",
"amount": 16
}
],
"inStock": false
},
{
"user": "6wb3f7ne35f40640m62p2gd",
"products": [
{
"type": "phones",
"amount": 2
},
{
"type": "clothes",
"amount": 15
}
],
"inStock": false
}
]
}
This the function outputting the above response
exports.getProducts = async (req,res) => {
const result = await Products
.find({inStock: false})
.select("-_id -createdAt -__v")
.exec()
if(!result) return res.status(400).json({ data: 'No product found' });
if(result.err) return res.json({ err: err });
return res.json({data: result});
}
But I want to get only products with the amount greater than 10
So my output should be like this
{
"data": [
{
"user": "83k13bde05f40640j12075w",
"products": [
{
"type": "shoes",
"amount": 20
}
],
"inStock": false
},
{
"user": "9dc3f7de05f40640j12075y",
"products": [
{
"type": "chairs",
"amount": 11
},
{
"type": "bags",
"amount": 16
}
],
"inStock": false
},
{
"user": "6wb3f7ne35f40640m62p2gd",
"products": [
{
"type": "clothes",
"amount": 15
}
],
"inStock": false
}
]
}
I tried using
.find({'products.amount': { $gt: 10 }})
But It didn't filter out the response
Did you try the $elemMatch operator ?
const result = await Products
.find({
inStock: false,
products: { $elemMatch: { amount: { $gt: 10 } } }
})
.select("-_id -createdAt -__v")
.exec();
You can use aggregation to achieve this.
First of all you use $match operator to find the documents with items in the array that match with your criteria. Then you can use $project and $filter operator to return the array filtered.
const result = await Products.aggregate([
{
"$match" : {
"products" : {
"$elemMatch" : { amount: { $gt: 10 } }
},
}
},
{
$project: {
user: 1,
inStock: 1,
products: {
$filter: {
input: "$products",
as: "products",
cond: { $gt: ["$products.amount", 10] }
}
}
}
}
])
.select("-_id -createdAt -__v")
.exec();
For further reading: https://studio3t.com/knowledge-base/articles/filter-elements-from-mongodb-arrays/#how-to-use-filter-and-project
I am making a simple api which has like document of each post.The like post has array of object of likes of that post.I want to like object into likes only if the document is not exist and if exist remove the object from likes array.I have use element match operator
but it does not work.How can I achieve this.Thanks in advance.
The code is
router.post("/like",(req,res)=>{
likeModel.find({ postId: req.body.postId }, async (err, doc) => {
console.log(req.body.postId)
console.log(doc.length+"s ");
if (!doc.length) {
const like = new likeModel({
postId: req.body.postId,
likes: [
{
userId: userId,
isNotified: isNotified,
},
],
});
await like.save((err, doc) => {
if (err) res.json({ "message": "error" });
else res.json(doc);
});
}
if (err) {
res.json({ "message": "error"});
}
else{
likeModel.find({
postId:req.body.postId,
likes:{
$elemMatch:{
userId:req.body.userId
}
}
},(err,doc)=>{
console.log(doc.length)
if(err){
res.json({"message":"error"})
}
else if(!doc.length){
likeModel.updateOne(
{ _Id: req.body.postId },
{
$push: {
likes:req.body.likes
},
},
(err, doc) => {
if (err) res.json({ "message": "err" });
else res.json(doc);
}
);
}
else{
likeModel.updateOne({
postId:req.body.postId
},{
"$pull":{
"likes":{
"userId":req.body.userId
}
}
},(err,doc)=>{
if(err){
res.json({"message":err})
}
else{
res.json(doc)
}
}
)
}
}
})
})
The document looks like
[
{
"_id": "62f8556861c9b1029e7a07b8",
"postId": "62f5fb7d74033aeac1e06399",
"likes": [
{
"userId": "62f5d6bee2310e3c71e10e36",
"isNotified": true,
"_id": "62f8556861c9b1029e7a07b9"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f865ed2a055ef17214a6ea"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f866192a055ef17214a6f1"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f8668c5ca6a649fc89cc3b"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f866b3c2041b73ea8d9d8a"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f867b6545168c7cd377b17"
},
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f868cf3255b839e1ca047b"
}
],
"__v": 0
},
{
"_id": "62f866192a055ef17214a6ed",
"postId": "62f5fb7e74033aeac1e0639d",
"likes": [
{
"userId": "62f5d9c2b30ecc8ca84c0242",
"isNotified": true,
"_id": "62f866192a055ef17214a6ee"
}
],
"__v": 0
}
]
I need to remove the domain name from the URL in the JSON array stored in Mongo DB using Mongoose.
JSON Array format in DB
{
"_id": {
"$oid": "602a482223df2a16e26f51bc"
},
"message": "Test Again",
"pollType": {
"$numberInt": "1"
},
"type": "TEST",
"optionList": [
{
"name": "name",
"original": "https://name/test/pictures/1613383695668-71393-0d1f829222f945dc",
"thumbnail": "https://name/test/pictures/1613383695668-71393-0d1f829222f945dc",
"vote": {
"$numberInt": "1"
},
"_id": {
"$oid": "602a482223df2a16e26f51b9"
},
"participateUser": [
{
"$oid": "5c9baa00bcafa608891b0b44"
}
],
"latestParticipate": [
{
"$oid": "5c9baa00bcafa608891b0b44"
}
]
},
{
"name": null,
"original": "https://name/test/pictures/1613383695672-71393-e92a34eaf6b48b19",
"thumbnail": "https://name/test/pictures/1613383695672-71393-e92a34eaf6b48b19",
"vote": {
"$numberInt": "0"
},
"_id": {
"$oid": "602a482223df2a16e26f51ba"
},
"participateUser": [
]
},
{
"name": null,
"original": "https://name/test/pictures/1613383695630-71393-3387191491ba279c",
"thumbnail": "https://name/test/pictures/1613383695630-71393-3387191491ba279c",
"vote": {
"$numberInt": "0"
},
"_id": {
"$oid": "602a482223df2a16e26f51bb"
},
"participateUser": [
]
}
],
"pollId": {
"$oid": "602a482223df2a16e26f51b8"
},
"createdAt": {
"$date": {
"$numberLong": "1613383714396"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1613383714396"
}
},
"totalVoteCount": {
"$numberInt": "1"
},
"participateUser": [
{
"$oid": "5c9baa00bcafa608891b0b44"
}
]
}
I am using below code to replace a string
return new Promise(async (resolve, reject) => {
console.log("Iam called")
MongoClient.connect('mongoDBconfig', function (err, client) {
if (err) throw err;
var collection = "test"
var db = client.db('testDB');
db.collection(collection).updateMany({
"optionList.thumbnail": { $regex: /name/ },
}, {
"$set": {
"optionList.$.thumbnail": {
$replaceOne: { input: "optionList.$.thumbnail", find: "https://name/test", replacement: "" },
}
}
}
}, function (error, success) {
if (success) {
resolve(success)
}
else {
reject(error)
}
})
})
})
but when I call this function I getting below error
DB Error : Duplicate Entry : dollar ($) prefixed field '$replaceOne' in 'optionList.0.original.$replaceOne' is not valid for storage.
The $replaceOne is a aggregation operator starting from MongoDB v4.4, you can use update with aggregation pipeline starting from MongoDB v4.2
$map to iterate loop of optionList array
$replaceOne to replace string
$mergeObjects to merge current object with updated original field
let originalName = "https://name/test";
db.collection(collection).updateMany(
{ "optionList.original": { $regex: originalName } },
[{
$set: {
optionList: {
$map: {
input: "$optionList",
in: {
$mergeObjects: [
"$$this",
{
thumbnail: {
$replaceOne: {
input: "$$this.thumbnail",
find: originalName,
replacement: ""
}
}
}
]
}
}
}
}
}],
function (error, success) {
if (success) { resolve(success) }
else { reject(error) }
}
)
Playground
Following is the Sample Workspace document.I want to update box positions when we drag and drop at front end.
{
"_id": ObjectId("5eaa9b7c87e99ef2430a320b"),
"logo": {
"url": ".../../../assets/logo/dsdsds.png",
"name": "testUpload"
},
"name": "My World",
"sections": [{
"box": [{
"_id": ObjectId("5da87b33502d6c634b3aa7ce"),
"name": "Meran To",
"position": 0
},
{
"_id": ObjectId("5da87b33502d6c7d873aa7d0"),
"name": "Documentation",
"position": 2
},
{
"_id": ObjectId("5da87b33502d6cdbb93aa7cf"),
"name": "File Manager Upload File Drive",
"position": 1
},
{
"_id": ObjectId("5da87b33502d6c276a3aa7cd"),
"name": "File Manager Upload File Drive",
"position": 1
}
],
"id": 1,
"title": "Simplicity",
"description": "Follow your barriers"
},
{
"box": [],
"id": 2,
"title": "xfxdfxcx 34",
"description": "sdsdsd sfsfsd ewrewrewre"
}
]
}
I send the updated positions from front-end to back-end via API, in an array as shown below.
[
{
"id": "5da87b33502d6c634b3aa7ce",
"position": 0
}, {
"id": "5da87b33502d6c7d873aa7d0",
"position": 1
}, {
"id": "5da87b33502d6cdbb93aa7cf",
"position": 2
}, {
"id": "5da87b33502d6c276a3aa7cd",
"position": 3
}]
I am currently updating DB using the below code
for (const el of req.body) {
await this.model.updateOne({
_id: req.params.workspaceId,
sections: {
$elemMatch: {
id: req.params.sectionId
}
},
'sections.box': {
$elemMatch: {
_id: el.id
}
},
}, {
$set: {
'sections.$[outer].box.$[inner].position': el.position
}
}, {
arrayFilters: [{
'outer.id': req.params.sectionId
}, {
'inner._id': el.id
}],
upsert: false,
});
}
But this is not the best method, it hits DB multiple times.
so I need to optimize this code with mongoose query itself.
May be using $set / $push.I don't know any exact methods.
So basically we need to remove the external for loop and make it work with mongoose itself.This is my requirement.
Thanks in advance for all the support.
There are 2 methods for doing it.
bulkWrite
const bulkOps = [];
req.body.forEach((el) => {
const upsertDoc = {
updateOne: {
filter: {
_id: req.params.workspaceId,
sections: {
$elemMatch: {
id: req.params.sectionId
}
},
'sections.box': {
$elemMatch: {
_id: el.id
}
},
},
update: {
$set: {
'sections.$[outer].box.$[inner].position': el.position
}
},
arrayFilters: [{
'outer.id': req.params.sectionId
}, {
'inner._id': el.id
}],
upsert: false,
}
};
bulkOps.push(upsertDoc);
});
const result = await this.model.collection.bulkWrite(bulkOps);
bulkUpdate
const bulkUpdate = this.model.collection.initializeUnorderedBulkOp();
req.body.forEach((el) => {
bulkUpdate.find({
_id: req.params.workspaceId,
sections: { $elemMatch: { id: req.params.sectionId } },
'sections.box': { $elemMatch: { _id: el.id } },
}).arrayFilters([{ 'outer.id': req.params.sectionId }, { 'inner._id': el.id }])
.updateOne({ $set: { 'sections.$[outer].box.$[inner].position': el.position }
});
});
await bulkUpdate.execute();
I'm trying to delete a subdocuments in array with Mongoose.
My datas :
{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb762"
},
"spaces": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76f"
},
"name": "Building 2",
"subSpace": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb771"
},
"name": "Basement"
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb770"
},
"name": "Floors"
}]
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76c"
},
"name": "Building 4",
"subSpace": [{
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76e"
},
"name": "Basement"
}, {
"_id": {
"$oid": "5d88dfe45feb4c06a5cfb76d"
},
"name": "Floors"
}]
}]
}
For this example, we want to delete the subSpace Floors in Building 2 with this _id : 5d88dfe45feb4c06a5cfb771
My code (in the model) :
exports.removeSubSpaceById = (subSpaceId) => {
Residence.findOneAndUpdate( { "spaces.subSpace._id": '5d88dfe45feb4c06a5cfb771' },
{ $pull:
{ spaces:
{ subSpace:
{ _id: '5d88dfe45feb4c06a5cfb771' }}}}, function(err, result) {
console.log(result);
})
};
Output : console.log : my entire document
But the subSpace/Basement (5d88dfe45feb4c06a5cfb771) is still in my document.
Thanks for your help.
Use positional operator for nested array operations. MongoDb Docs
exports.removeSubSpaceById = (subSpaceId) => {
Residence.findOneAndUpdate({ "spaces._id": '5d88dfe45feb4c06a5cfb76f' },
{
$pull:
{
"spaces.$.subSpace": { _id: "5d88dfe45feb4c06a5cfb771" }
}
}, function (err, result) {
console.log(result);
})
}