I have a object that I want to update using findOneAndUpdate but it seems it's not working.. I already tried to use $ operator but it's not working but once I remove $ operator the call shows error of.
MongoServerError: Cannot create field 'categoryfilter' in element {store: [ { productname: "monitor", price: 1500, quantity: 5, categoryfilter: "Monitors", description: "tests", timestamp: "December 24th 2021, 1:39:36 pm", _id: ObjectId('61c55d687d8ff305de3ed044'), 0: { categoryfilter: "Monitors", description: "testsss", price: 1500, productname: "monitor", quantity: 5, timestamp: "December 24th 2021, 1:39:36 pm" } } ]} at MessageStream.messageHandler (C:\Users\gamex\Desktop\my files\goldenwell\server\node_modules\mongodb\lib\cmap\connection.js:467:30)
at MessageStream.emit (events.js:376:20)
at processIncomingData (C:\Users\gamex\Desktop\my files\goldenwell\server\node_modules\mongodb\lib\cmap\message_stream.js:108:16)
at MessageStream._write (C:\Users\gamex\Desktop\my files\goldenwell\server\node_modules\mongodb\lib\cmap\message_stream.js:28:9)
at writeOrBuffer (internal/streams/writable.js:358:12)
at MessageStream.Writable.write (internal/streams/writable.js:303:10)
at TLSSocket.ondata (internal/streams/readable.js:745:22)
at TLSSocket.emit (events.js:376:20)
at addChunk (internal/streams/readable.js:309:12)
at readableAddChunk (internal/streams/readable.js:284:9) {
operationTime: new Timestamp({ t: 1640325515, i: 17 }),
ok: 0,
code: 28,
codeName: 'PathNotViable',
'$clusterTime': {
clusterTime: new Timestamp({ t: 1640325515, i: 17 }),
signature: {
hash: new Binary(Buffer.from("c08511e0a3727ac6636aa2c56b4587cfcf0c2396", "hex"), 0),
keyId: new Long("7013342858887299079")
}
}
}
here's my Schema I created using mongoose.
import mongoose from 'mongoose';
const OwnerSchema = mongoose.Schema({
username: {
require: true,
type: String,
},
password: {
require: true,
type: String,
},
isAdmin: {
type: Boolean,
default: true,
},
store: [
{
productname: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
quantity: {
type: Number,
required: true,
},
categoryfilter: {
type: String,
required: true
},
description: {
type: String,
required: true,
},
imageBase64: {
type: String,
required: true,
},
timestamp: {
type: String,
required: true,
}
}
]
});
const OwnerModels = mongoose.model('OwnerModels', OwnerSchema);
export default OwnerModels;
here's my query for update. I've tried to use $ operator but it seems no use at all so removed it.
export const updateProduct = async (req,res) => {
const { id } = req.params;
try {
if(!mongoose.Types.ObjectId.isValid(id)) return res.status(404).json({ message: 'Invalid ID' });
await OwnerModels.findOneAndUpdate({'_id': id, store:{ $elemMatch: { productname: req.body.store[0].productname }}},
{$set:
{
"store.productname": req.body.store[0].productname,
"store.price": req.body.store[0].price,
"store.quantity": req.body.store[0].quantity,
"store.categoryfilter": req.body.store[0].categoryfilter,
"store.description": req.body.store[0].description,
"store.timestamp": req.body.store[0].timestamp
}
},
{new: true, safe: true, upsert: true}, (error, response) => {
if(error){
console.log(error)
}else{
console.log(response)
}
}
);
} catch (error) {
res.status(404).json(error)
}
}
CodePudding user response:
Because store
is an array, mongodb cannot know which element in store
to update by your { $set: { 'store.categoryfilter': ... } }
statement.
The $elemMatch
query is just for query filter at document level, it will not pick the specific store
element out to update.
The right choice is to use arrayFilter in update statement
CodePudding user response:
Try to retrieve the OwnerModel
with a findByid
and then update the store
array using the push
method.
You will need to save the updated object using the save
method.
const owner = await OwnerModels.findByid(id);
if (!owner) {
return res.status(404).json({ message: "Owner not found" });
}
owner.store.push(req.body.store);
await owner.save();
res.status(200).json({ message: "Updated" })
Finally, you may want to add a default
value to the imageBase64
field, since I don't see it listed in your body params:
imageBase64: {
type: String,
required: true,
default: ""
},