I am trying to remove logged-in users objectId from an array field called interest but it doesnt work.
model
const projectSchema = new mongoose.Schema({
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
isShowcase: {
type: Boolean,
required: false,
default: false
},
isCollab: {
type: Boolean,
required: false,
default: false
},
title: {
type: String,
required: true,
trim: true
},
description: {
type: String,
required: true,
trim: true
},
thumbnail: {
type: String,
required: true,
trim: true
},
media: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Media',
required: false,
}],
skillsNeeded: [{
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'Skill'
}],
contributors: [{
user: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'User'
},
role: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'Skill'
},
required: false,
}],
isOpen: {
type: Boolean,
required: false,
default: false
},
interest: [{
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'User'
}]
}, {
timestamps: true
})
the route to remove interest
// delete an interest on a collaboration
router.delete('/api/project/:id/apply', auth, async (req, res) => {
const project = await Project.findOne({ _id: req.params.id, isOpen: true })
if (!project) {
res.status(500).send({ "message": "you cannot show interest at the moment" })
}
try {
project.interest = project.interest.filter((objid) => {
return objid != req.user._id
})
await project.save()
console.log(project);
return res.status(204).send(project)
} catch (e) {
res.status(500).send()
}
})
below is the project I am trying to remove a users object id from the interest
{
"isShowcase": false,
"isCollab": true,
"media": [],
"skillsNeeded": [
"5f9fc49a0282a127e4aca0fa",
"5faa596e9d54a92ab805a7a9"
],
"isOpen": true,
"interest": [
"5fa35ac783fe7042fcbbf12a"
],
"_id": "5fb98a36cc3b62aa788adbe0",
"title": "American gods",
"description": "it a story about a war between new and old gods",
"thumbnail": "https://images-na.ssl-images-amazon.com/images/S/pv-target-images/fc3ef790bcbc143d2b5b76b454b7cdcc68a19d60f629e328121713590294a895._RI_V_TTW_.jpg",
"owner": "5fa4f0af4a7bf5471c41e225",
"contributors": [],
"createdAt": "2020-11-21T21:44:22.818Z",
"updatedAt": "2020-11-22T08:22:02.377Z",
"__v": 1
}
when I run the delete request to that route, I get status 204 but the project is not returned, and when I check back on the project, I still see the project with the user's objectID still in the array.
the logged-in users object
{
"skills": [],
"isEmailConfirmed": false,
"isAdmin": false,
"isActive": true,
"hasSpecialPrevilege": false,
"_id": "5fa35ac783fe7042fcbbf12a",
"fullname": "olayinka odedeyi",
"username": "yinkus",
"email": "olayinkaodedeyi#gmail.com",
"createdAt": "2020-11-05T01:52:07.378Z",
"updatedAt": "2020-11-22T10:37:08.307Z",
"__v": 4,
"bio": "a great girl"
}
Please, what could be preventing the logged-in user id from getting removed when the delete route to do that is run?
The problem lies in how you are comparing the two objectids in filter function. You need to use .equals() method available on objectId instance.
project.interest = project.interest.filter((objid) => {
return !objid.equals(req.user._id)
})
Related
I have a model which has a field with nested fields, when I try to update the field it doesn't work. it still remail=ns the same. Below is the code with further explanations.
i have a model below
const mongoose = require('mongoose')
const placeSchema = new mongoose.Schema({
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
typeof: {
type: String,
required: true,
enum: ["studio", "hall",
"house", "mansion",
"field", "room",
"restaurant", "school",
"church", "beach", "warehouse",
"others"
]
},
location: {
type: String,
required: true,
trim: true
},
time: {
alwaysopen: {
type: Boolean,
required: true,
default: false
},
open: {
type: String
},
close: {
type: String
}
},
idealfor: [{
type: String,
required: false,
enum: ["reception", "production",
"meeting", "performance",
"dinner", "wedding",
"party", "conference"
]
}],
rooms: {
type: Number,
required: false,
trim: true
},
toilet: {
type: Number,
required: false,
trim: true
},
price: {
type: Number,
required: true,
trim: true
},
amenities: [{
type: String,
required: false,
enum: ["electricity", "a/c",
"wifi", "sound system",
"private entrance",
"kitchen", "large table", "tv",
"green screen", "Stage",
"changing room", "makeup room",
"lounge", "soundproof"
]
}],
accessibility: [{
type: String,
required: false,
enum: ["wheelchair", "Elevator",
"on-site parking", "parking near by",
"Stairs"
]
}],
isOpen: {
type: Boolean,
required: false,
default: true
},
phonenumber: {
type: String,
required: true,
trim: true
},
}, {
timestamps: true
})
the problem is that when i try to update the time.alwaysopen field from false to true, id doesn't work.
below is the update route
// Edit a place
router.patch('/api/place/:id', isVerified, async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ["title", "description", "maxguest", "size", "isOpen", "rules", "rooms", "toilet", "price", "phonenumber", "location", "typeof", "time", "time.alwaysopen", "time.open", "time.close"]
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(404).send({ error: 'Invalid updates!' })
}
try {
const place = await Place.findOne({ _id: req.params.id, owner: req.user._id })
if (!place) {
return res.status(404).send({ "message": "place does not exist" })
}
updates.forEach((update) => place[update] = req.body[update])
await place.save()
res.status(201).send({place, "message": "successfully updated" })
} catch (e) {
res.status(400).send({ "message": "failed to update" })
}
})
and below is the patch json request i make
{
"time.alwaysopen": false
}
after sending the patch request, i still get the vaue of the time.alwaysopen to be true, but updating the field is fine.
below is the response i get
{
"place": {
"time": {
"alwaysopen": true
},
"idealfor": [
"production",
"wedding"
],
"amenities": [
"electricity",
"a/c",
"Stage"
],
"accessibility": [],
"unavailabledate": [],
"isOpen": true,
"img": true,
"_id": "604028e717314039402c2c10",
"typeof": "studio",
"location": "good news church, olufemi street, surulere, Lagos, Nigeria",
"rooms": 2,
"toilet": 2,
"price": 1000,
"phonenumber": "+2348125580085",
"owner": "603e6b494e0df045745066a7",
"createdAt": "2021-03-04T00:25:11.413Z",
"updatedAt": "2021-03-04T01:19:14.867Z",
"__v": 0,
"description": "the famous hotel",
"title": "Royal habiscus edited"
},
"message": "successfully updated"
}
Please, what could be the problem?
I am trying to soft delete an object from array using mongoose-delete lib
I Have a schema like that :
const mongooseDelete = require('mongoose-delete');
const number = new Schema({
allocation_date: { type: Date, required: true, default: Date.now() },
number: { type: String, required: true },
virtual_number: { type: String, required: true },
virtual_number_id: { type: Number, required: true, unique: true },
});
const schema = new Schema(
{
allocation_id: { type: String, required: true, unique: true },
numbers: { type: [number], required: true },
},
{
timestamps: true,
},
);
number.plugin(mongooseDelete, { deletedAt : true });
exemple data :
{
"_id": "5f7c14f9388ee9ebc0b28abc",
"allocation_id": "5_2_9387323_1"
"numbers": [
{
"allocation_date": "2020-10-06T06:55:41.197Z",
"_id": "5f7c14f997d996f7988fe8cf",
"number": "*********",
"virtual_number": "**********",
"virtual_number_id": *******,
},
{
"allocation_date": "2020-10-06T06:59:41.197Z",
"_id": "5f7c14f997d996f7988fe8cf",
"number": "*********",
"virtual_number": "**********",
"virtual_number_id": *******
}
],
"createdAt": "2020-10-06T06:55:53.367Z",
"updatedAt": "2020-10-06T06:55:53.367Z",
}
When I tried to use the delete method as follow :
const deleteNumber = await VirtualNumberAllocation.findOne(
{
'numbers.virtual_number': virtualNumber.virtualNumber,
allocation_id: virtualNumber.allocationID,
});
const activeVirtualNumber = deleteNumber.numbers.filter(
(number) => number.virtual_number==virtualNumber.virtualNumber,
);
await activeVirtualNumber[0].delete();
I'm getting this error in console:
mongoose: calling `save()` on a subdoc does **not** save the document to MongoDB, it only runs save middleware. Use `subdoc.save({ suppressWarning: true })` to hide this warning if you're sure this behavior is right for your app.
Does anyone have experience with soft deleting from an array using the library?
const projectSchema = mongoose.Schema({
title: { type: String, required: true, trim: true },
projectId: { type: String, required: true, trim: true, unique: true },
company: { type: mongoose.Schema.Types.ObjectId, ref: 'Company', required: true },
description: { type: String, trim: true },
remark: { type: String, trim: true },
active: { type: Boolean, required: true },
participants: [{
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
active: { type: Boolean, required: true },
timeSpent: [{
date: { type: Date, required: true },
hour: { type: Number, required: true }
}]
}]
});
I've searched through a lot of SO questions, but none of them seems to be able to solve my problem. Sometimes I need to update one of the field from one participant, I want to update it in a way that when
//this data to apply update on the first element of the participants array
const partialParticipantUpdate = {
active: false
}
can be easily update to the sub document without rewriting all the other property. Basically like findByIdAndUpdate not findByIdAndReplace. I've tried aggregation but its only for reading data not writing data. I've also tried
let p = await Project.update({
"_id": mongoose.Types.ObjectId("5ee22f90e550c32194fb7a91"),
"participants._id": mongoose.Types.ObjectId("5ee4b5bd4fdcdb0c8813f5f5")
}, {
"$set": { "participants.0": partialParticipantUpdate } })
console.log(p);
However some of the participants property is removed after the update
{
"_id": { "$oid": "5ee22f90e550c32194fb7a91" },
"title": "Geo Chart Example",
"projectId": "myId",
"company": { "$oid": "5ee22ca46c7fc4358ced20a1" },
"description": "asd",
"remark": "re",
"active": true,
"participants": [{
"_id": { "$oid": "5ee4f37f4d8c234cc02d405a" },
"active": false,
"timeSpent": []
},
{
"_id": { "$oid": "5ee4c8a955ed7f23445a3cbc" },
"user": { "$oid": "5ee0bdc318998236706b5e5a" },
"active": true,
"timeSpent": []
}
],
"__v": 0
}
The update did change the first participant's "active" property from true to false, but it also lost some of the property like "user" and "timeSpent" array will get emptied as well
Finally I found the solution
const partialParticipantUpdate = {
active: false
}
let p = await Project.findById("5ee22f90e550c32194fb7a91");
let x = p.participants.id("5ee7224be4e4386084b87d3c");
x.set(partialParticipantUpdate);
let response = await p.save({ validateBeforeSave: false });
console.log(response);
The only downside is that I have to communicate with mongoose twice
I'm building an API in NodeJS Express and MongoDB using Mongoose.
I created a Profile model that embeds the Experience schema.
Like:
{
"_id": "5e26ff6d5be84a3aeeb2f7bb",
"username": "some"
<fields of the profile>
"experience": [
{
"image": "",
"createdAt": "2020-01-21T13:41:01.873Z",
"updatedAt": "2020-01-21T13:41:01.873Z",
"_id": "5e26ff6d5be84a3aeeb2f7bc",
"title": "Senior Dev",
"role": "Dev",
"company": "ArosaDev",
"startDate": "2018-12-03T23:00:00.000Z",
"endDate": null,
"description": "",
"area": ""
}
],
"createdAt": "2020-01-21T13:41:01.874Z",
"updatedAt": "2020-01-21T13:41:01.874Z",
"__v": 0
}
The problem is I have to create an endpoint GET which gets for one profile all the experiences.
experienceRouter.get("/:username", async(req, res) => {
console.log(req.params.username);
const experiences = await Profiles.findOne({"username":req.params.username} ??? );
res.send(experiences);
});
I know I should select the embedded field experience and get back all the experiences but I don't know how should I do with Mongoose in my route.
I don't know what comes next after I select the username and how I can select the all experience for the username I'm requested.
I'm new to this and cannot find any good references explaining to me that for good.
I will appreciate an example of how a route like this should be done.
My model:
// Profile Schema model
// Embedded we have the Experience as []
const mongoose = require("mongoose");
const { isEmail } = require("validator");
const experienceSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date
},
description: {
type: String
},
area: {
type: String
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
})
const profileSchema = new mongoose.Schema({
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: true,
validate: {
validator: string => isEmail(string),
message: "Provided email is invalid"
}
},
bio: {
type: String,
required: true
},
title: {
type: String,
required: true
},
area: {
type: String,
required: true
},
imageUrl: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
},
username: {
type: String,
required: true,
unique: true
},
experience: [
experienceSchema
],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
});
const collectionName = "profiles";
const Profile = mongoose.model(collectionName, profileSchema);
module.exports = Profile;
replace your code with below
You can mention your fields which you need in the second argument of function this is called projection as mentioned
So for including of fields use 1 and for excluding fields use 0
experienceRouter.get("/:username", async(req, res) => {
console.log(req.params.username);
const profile = await Profiles.findOne({"username":req.params.username},{experience:1 ,username:1, _id:0}).lean();
res.send(profile);
});
I am using mongo DB with node.js and all models is in common folder and using virtual population to communicate between the models.For Example model1->model2->model3(model1 have the dependencies of model2 and model2 have the dependencies of model3).
Here is the code:
var packageGroupSchema = new Schema(
{
packageGroupCode: { type: String, required: true, unique: true},
packageGroupName: { type: String, required: true },
description: String,
**moduleId: { type: Schema.Types.ObjectId, required: true },**
active: Boolean,
createdDate: { type: Date, default: Date.now},
lastUpdatedDate: { type: Date, default: Date.now}
},
{
toJSON: { virtuals: true }
}
);
packageGroupSchema.virtual('moduleData', {
ref: 'Module',
localField: 'moduleId',
foreignField: '_id',
justOne: true
});
2nd Model:
//module Schema
var moduleSchema = new Schema(
{
moduleCode: { type: String, required: true, unique: true},
moduleName: { type: String, required: true },
description: String,
**categoryId: { type: Schema.Types.ObjectId, required: true },**
active: Boolean,
createdDate: { type: Date, default: Date.now},
lastUpdatedDate: { type: Date, default: Date.now}
},
{
toJSON: { virtuals: true },
toObject: {virtuals: true}
}
);
moduleSchema.virtual('categoryData', {
ref: 'Category',
localField: 'categoryId',
foreignField: '_id',
justOne: true
});
If I am runing the api for first model so I am geeting the data of dependencris(category) form the 2nd model.
Here is the result I am getting:
{
"_id": "59410a5dab85113a7cdc0507",
"packageGroupCode": "P02",
"packageGroupName": "package2",
"description": "package2",
"moduleId": "5940efeadb8fe72a8cb4e056",
"active": true,
"__v": 0,
"lastUpdatedDate": "2017-06-14T11:30:43.798Z",
"createdDate": "2017-06-14T11:30:43.798Z",
"moduleData": {
"_id": "5940efeadb8fe72a8cb4e056",
"moduleName": "module name",
**"categoryData": null,**
**"id": "5940efeadb8fe72a8cb4e056"**
},
**"id": "59410a5dab85113a7cdc0507"**
}
Can anybody tell me what I have to do to ignore catergoryData in moduleDate and id repetition.
Expexted JSON should be like this:
{
"_id": "59410a5dab85113a7cdc0507",
"packageGroupCode": "P02",
"packageGroupName": "package2",
"description": "package2",
"moduleId": "5940efeadb8fe72a8cb4e056",
"active": true,
"__v": 0,
"lastUpdatedDate": "2017-06-14T11:30:43.798Z",
"createdDate": "2017-06-14T11:30:43.798Z",
"moduleData": {
"_id": "5940efeadb8fe72a8cb4e056",
"moduleName": "module name"
}
}
if your result is stored in "theObject" you can remove the keys like this:
delete theObject["id"];
delete theObject["moduleData"]["id"];
delete theObject["moduleData"]["categoryData"];