Reputation: 33
I am able to update: deviceName, macAddress, and blacklisted, but any values in the connection object will not update (ie: active, connectionURL & configuration). The purpose of the if statements are to not modify the values in the database if the user left them blank.
Schema:
const deviceSchema = new Schema({
deviceName: { type: String, required: true, trim: true },
macAddress: { type: String, required: true, unique: true, trim: true },
blacklisted: {type: Boolean, required: true},
connection: { type: Object, required: true,
active: { type: Boolean, required: true, trim: true },
connectionUrl: { type: String, required: true, trim: true},
configuration: { type: String, required: true, trim: true},
},
}, {
timestamps: true,
});
Updating Database:
router.route('/update/config/:id').post((req, res) => {
Device.findById(req.params.id)
.then(device => {
device.macAddress = req.body.macAddress;
device.connection.active = req.body.active;
if (req.body.connectionUrl != '' && req.body.connectionUrl != "Choose...") {
device.connection.connectionUrl = req.body.connectionUrl;
}
if (req.body.configuration != '') {
device.connection.configuration = req.body.configuration;
}
device.save()
.then(() => res.json('device configuration(s) updated!'))
.catch(err => res.status(400).json('Error: ' + err));
})
.catch(err => res.status(400).json('Error: ' + err));
});
Upvotes: 3
Views: 455
Reputation: 1235
In Mongoose, if you're assigning a Schema the type of 'Object', it will become a Mixed schema, which means a couple things, but the most important of which in your case is that mongoose cannot automatically detect changes to that part of the document.
What you're likely looking for here is either a 'Nested Path' or a 'SubDocument'. See here for more information on the difference between the two.
The gist is, you need to change how you're defining the schema. There's a few options here:
In this case, your best bet is a 'nested path', which would be defined like so:
const deviceSchema = new Schema({
deviceName: { type: String, required: true, trim: true },
macAddress: { type: String, required: true, unique: true, trim: true },
blacklisted: {type: Boolean, required: true},
connection: {
active: { type: Boolean, required: true, trim: true },
connectionUrl: { type: String, required: true, trim: true},
configuration: { type: String, required: true, trim: true},
},
}, {
timestamps: true,
});
In this case, you're going to want to use a SubDocument
const connectionSchema = new Schema({
active: { type: Boolean, required: true, trim: true },
connectionUrl: { type: String, required: true, trim: true },
configuration: { type: String, required: true, trim: true },
}, { timestamps: false });
const deviceSchema = new Schema({
deviceName: { type: String, required: true, trim: true },
macAddress: { type: String, required: true, unique: true, trim: true },
blacklisted: {type: Boolean, required: true},
connection: { type: connectionSchema, required: true },
}, {
timestamps: true,
});
EDIT: In reference to a question posted in a comment below: If you want to be able to reference the same connectionSchema from multiple 'deviceSchema's, you would need to change to something along the lines of this:
const deviceSchema = new Schema({
deviceName: { type: String, required: true, trim: true },
macAddress: { type: String, required: true, unique: true, trim: true },
blacklisted: {type: Boolean, required: true},
connection: { type: Schema.Types.ObjectId, required: true, ref: "Connection" },
}, {
timestamps: true,
});
In this situation, you would also need to be certain that you're explicitly creating both models (a Device model, and a Connection model), and to ensure the connection model is loaded with the device model, you would then run:
DeviceModel.findOne(/*whatever*/).populate('connection')
rather than your normal 'find' method. This is getting a bit far afoot from the original question though.
Here, you can use the built in 'Mixed' type as you were already, but it comes with the caveat that you can't define any further children, and mongoose won't automatically detect changes to that portion of the document, meaning device.save()
won't update anything in your connection object automatically.
const deviceSchema = new Schema({
deviceName: { type: String, required: true, trim: true },
macAddress: { type: String, required: true, unique: true, trim: true },
blacklisted: {type: Boolean, required: true},
connection: { type: Object, required: true },
}, {
timestamps: true,
});
In order to tell mongoose that the connection field has been updated, we would have to call device.markModified('connection')
before device.save()
Upvotes: 1