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?
Related
little bit stuck with mongoose. I want to get all users projects where he's added. Tried few options, but in all of them I receive an empty array. So the main question is it possible somehow to find all project by filtering/finding the Project model?
This is how looks my default response to understand what I'm looking for:
{
"_id": "61a8bc4e8e24f10ac7a7288d",
"name": "Random project",
"description": "Random project desc",
"maxWorkingEmployees": 5,
"status": "Paused",
"createdBy": {
"_id": "61a66578f2dabf7555bcf4ab",
"email": "Henrikas#furniture1.eu",
"role": "Owner"
},
"currentlyWorkingEmployees": [
{
"username": "Ema",
"role": "Employee",
"_id": "61a8e0423140ecce769dc971"
}
],
"createdAt": "2021-12-02T12:30:06.461Z",
"updatedAt": "2021-12-02T15:11:51.361Z",
"__v": 0
}
Project model:
const mongoose = require('mongoose');
const SingleUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
role: {
type: String,
required: true,
},
});
const ProjectSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Provide project name'],
minlength: 5,
},
description: {
type: String,
required: [true, 'Provide description about the project'],
},
maxWorkingEmployees: {
type: Number,
required: [
true,
'Provide maximum number of employees working on this project',
],
},
currentlyWorkingEmployees: [SingleUserSchema],
status: {
type: String,
enum: ['Pending', 'In progress', 'Paused', 'Delayed', 'Completed'],
default: 'Pending',
},
createdBy: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model('Project', ProjectSchema);
Here's my controller and my first try:
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.find({
currentlyWorkingEmployees: { _id: userId },
});
res.json({projects});
};
Second shot after reading some articles
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.aggregate([
{
$match: {
currentlyWorkingEmployees: { _id: userId },
},
},
]);
};
As I said in the comment you can do it accessing to the internal object of the schema with an string accessing to it child object.
Project.find({'currentlyWorkingEmployees._id': userId})
I am trying to load default data into my MongoDB database from a node.js backend.
This is the data I am loading as JSON:
[
{
"datetime": "28/08/2021 16:01:00",
"sensor": {
"id": 1,
"type": "Temperature"
},
"value": 2502
},
{
"datetime": "28/08/2021 16:02:00",
"sensor": {
"id": 2,
"type": "Temperature"
},
"value": 2252
}
]
And these are the mongoose models:
const SensorType = Object.freeze({
Temperature: "Temperature"
});
const SensorSchema = new mongoose.Schema({
id: { type: Number, required: true },
type: { type: Object.values(SensorType), required: true },
});
Object.assign(SensorSchema.statics, { SensorType });
const Sensor = mongoose.model('Sensor', SensorSchema);
const DataEntrySchema = new mongoose.Schema({
datetime: { type: String, required: true },
sensor: { type: SensorSchema, required: true },
value: { type: Number, required: true }
});
const DataEntry = mongoose.model('DataEntry', DataEntrySchema);
Loading the DataEntries like this:
mongoose.connect("mongodb://127.0.0.1:27017/",{
useCreateIndex:true,
useNewUrlParser: true,
useUnifiedTopology: true}
).then(() => {
console.log('Database Successfully Connected')
if(fill_default_data) {
DataEntry.create(
JSON.parse(fs.readFileSync(path.resolve(__dirname, 'test_data.json'), 'utf8'))
);
}
}, error => {
console.log(error)
}
);
However, I am noticing that no Sensor-objects are created inside MongoDB, only DataEntries - why is that? And how can I create Sensor-objects as well?
Of course, a DataEntry object has the sensor attached but if I call Sensor.find().then( sensors => res.json(sensors) ) an empty array is returned.
You probably can't use a schema in another schema. You need to use refs instead.
So something like this sensor: { type: SensorSchema, required: true } won't work.
You should replace it with sensor: { type: number, required: true, ref: 'Sensor' },, where the ref is the name of the model you want to refer to as a string. Notice that the type is a number as you want to pass the id of the relevant SensorDocument in the DataEntryDocument.
Moreover id is a virtual, you should use _id instead when you want to spec out ids in mongoose schemes.
So your mongoose schemes should look like:
const SensorSchema = new mongoose.Schema({
_id: { type: mongoose.Schema.Types.Number, required: true },
type: { type: mongoose.Schema.Types.String, required: true },
});
const Sensor = mongoose.model('Sensor', SensorSchema);
const DataEntrySchema = new mongoose.Schema({
datetime: { type: mongoose.Schema.Types.String, required: true },
sensor: { type: mongoose.Schema.Types.Number, ref: 'Sensor', required: true },
value: { type: mongoose.Schema.Types.Number, required: true }
});
const DataEntry = mongoose.model('DataEntry', DataEntrySchema);
I still don't know why the Object.freeze and Object.assign are here.
Now if you want a DataEntry, you first need to create a Sensor.
const sensor = new Sensor({ _id: 0, type: 'Temperature' })
await sensor.save()
const dataEntry = new DataEntry({ sensor: 0, datetime: 'some timestamp as string', value: 25 })
await dataEntry.save()
I am leaving the validation-specific logic out as it is out of the scope of this query.
You can checkout docs for mongoose populate for more information.
I've been trying updateOne, findOneAndUpdate, and update. Nothing has worked. findOne() operation returns the correct documents.
userProfileModel.updateOne(
{ userEmail },
{
$push: {
userFavLocation: payload,
},
},
(err, result) => {
console.log(err);
console.log(result);
}
);
I get this but no change in my document.
{ ok: 0, n: 0, nModified: 0 }
userEmail and payload have the correct value. When I do findOneAndUpdate, it returns correct document but won't push the value.
This is the Schem for the user profile
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserProfileSchema = new Schema(
{
userEmail: {
type: String,
required: true,
unique: true,
},
userProfilePictureUrl: {
type: String,
},
userSignUpDate: {
type: Date,
},
userId: {
type: String,
required: true,
unique: true,
},
userFirstName: {
type: String,
required: true,
},
userLastName: {
type: String,
required: true,
},
userGender: {
type: String,
required: true,
},
userBirthday: {
type: Date,
required: true,
},
userCoordinates: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number],
},
},
userFavFacilities: {
type: Object,
},
userHometown: {
address: Object,
},
userContact: {
friends: Object,
},
userOrganizations: {
organizations: Object,
},
userMessages: {
type: Object,
},
userAlerts: {
type: Object,
},
userRoles: Object,
userFacilities: Object,
},
{ collection: 'userprofilemodels' }
);
UserProfileSchema.index({ location: '2dsphere' });
module.exports = UserProfile = mongoose.model(
'userprofilemodels',
UserProfileSchema
);
You have to add the userFavLocation field to your schema or mongoose won't perform the update.
const UserProfileSchema = new Schema(
{
userEmail: {
type: String,
required: true,
unique: true,
},
userFavLocation: [PUT_ARRAY_ITEM_TYPE_HERE],
...
}
}
i have 2 Schemas. 1. ProjectBug and 2. ProjectBugImage so i am uploading an image and saving it in a different collection.
See the Schemas below Number 1
const mongoose = require('mongoose');
let ProjectBugSchema = new mongoose.Schema({
projectID: {
type: mongoose.Schema.ObjectId
},
completed: {
type: Boolean,
default: false
},
components: Boolean,
groupSelect: String,
appsAffected: Array,
title:String,
description:String,
selectedcomponents: Array,
resources: Array,
isLive: Boolean,
issueNumber: String,
projectBugMianID: String,
date: String,
reporter: String,
foundOn: String,
testedDevel: Boolean,
testedLive: Boolean,
testedStaging: Boolean,
platform: String,
linked: Boolean,
linkedTo: String,
type: String,
appPassword: String,
appUsername: String,
percentageComplete: String,
status: String,
releaseID: {
type: String
},
createdAt:{
type: Date,
default: Date.now
},
},{
timestamps: true
},{
toJSON: { virtuals: true },
toObject: { virtuals: true },
});
ProjectBugSchema.virtual('bugImage', {
ref: 'bugImage',
localField: '_id',
foreignField: 'bugID'
});
module.exports = mongoose.model('ProjectBug', ProjectBugSchema);
Number 2
const mongoose = require('mongoose')
const ProjectBugImageSchema = new mongoose.Schema({
bugID:{
type: mongoose.Schema.ObjectId,
},
fileName:{
type: String,
},
path: {
type: String,
},
createdAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('bugImage', ProjectBugImageSchema)
And then i my controller i have
exports.index = (req, res) => {
ProjectBug.find({})
.populate('bugImage', '', null, { })
.exec((err, bugs) => {
if(err){
res.send(err)
}
res.send(bugs)
})
}
Strange thing is this used to work, and now it does not anymore, as you can see i have the ProjectbugSchema.vertual('bugImage', {...}) with the ref to bugImage and the local field to _id and foreignField to 'bugID' so that would match the ProjectBugImage.bugID with the local field of ProjectBug _id
what i get when i get data. Response
{
"completed": false,
"appsAffected": [],
"selectedcomponents": [],
"resources": [],
"_id": "5e8195fcc7939644cc322793",
"groupSelect": "",
"title": "asdasd",
"description": "<p>asdasd</p>",
"issueNumber": "",
"date": "2020-03-30",
"reporter": "5d305d3a9fe62f5578d0e209",
"type": "bug",
"foundOn": "",
"isLive": false,
"testedDevel": false,
"testedLive": false,
"testedStaging": false,
"platform": "",
"appUsername": "",
"appPassword": "",
"percentageComplete": "",
"status": "",
"createdAt": "2020-03-30T06:47:24.751Z",
"updatedAt": "2020-03-30T06:47:24.751Z",
"__v": 0
}
All i want is all the images that has bugID to be with the projectbug where the ids match. and put them into an array. Am i doing something wrong in the populate?? or somewhere else?
So i figured it out, in the model where i create the virtual i had
,{
toJSON: { virtuals: true },
toObject: { virtuals: true },
});
I took that out closed the Schema and underneath i put
ProjectBugSchema.set('toObject', { virtuals: true })
ProjectBugSchema.set('toJSON', { virtuals: true })
Small change but seems to be the answer.
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);
});