Here is my situation:
I have a simple Schema that has an object called commands which I originally set to {}
.
commands:{}
When I went to add a document to the database, I looped through a file of commands and added them to the object by doing command["command"] = "blah blah";
. The way I did that is as follows (The code I work is quite old):
Guild.findOne({guildId:serverId}).then(x=>{
x.commands = {};
for(let command of Object.values(commandInfo)){
if(!command.name) continue;
const getSubs = ()=>{
const subArray = {};
if(!command.subCommands) return;
for(let subs of Object.values(command.subCommands)){
subArray[subs.name] = {
access:subs.access,
disabled:subs.disabled
}
}
x.commands[command.name].subCommands = subArray;
}
x.commands[command.name] = {
access:command.access,
bounded:command.bounded,
disabled:command.disabled,
}
getSubs();
}
console.log("Success!");
x.save();
});
The commands contain the following (I'll use two commands for my example):
work:{
access:"All",
bounded:"A Channel",
disabled:false
},
profile:{
access:"All",
bounded:"Another Channel",
disabled:false,
subCommands:{
bio:{
access:"All",
disabled:true
}
register:{
access:"All",
disabled:false
}
}
Fastforwarding to now, I made a config file that is supposed to edit these commands. The code I wrote works perfectly fine; however, Mongoose is unable to save any of the command's changes. Everything else in my Schema works in the config file except anything related to commands.
I know what the problem. Mongoose can't find the command in the Schema and gets confused somehow. And I know I could fix it by adding all of the commands and their properties to the Schema. The only problem with that is it's tedious and is not a clean solution to me adding any new commands. Plus, I have all of the information for the commands in a separate file, so I don't want to rewrite what I already wrote.
My question is: is there a workaround to my problem? I tried setting commands to Schema.Types.Mixed
, but that didn't fix it. I also searched all around for something similar but could not find anything.
Here is the full Schema as requested:
const {Schema, model} = require("mongoose");
const settings = require("../utils/settings");
const guildSchema = Schema({
guildId:String,
symbols:{
prefix:{type:String, default:";"},
currency:{type:String, default:"$"}
},
channels:{
casinoChannels:Array,
fineChannels:Array
},
commands:Schema.Types.Mixed,
hierarchy:[{
name:String,
role:{type:String, default:""},
members:Array
}],
users:[{
userId:String,
cash:Number,
bank:Number,
items:[{
name:String,
amount:Number
}],
timers:{
work:String,
crime:String,
hack:String,
steal:String,
daily:String,
weekly:String,
marry:String,
divorce:String,
idea:String,
report:String,
quiz:String
},
fine:{
fineId:String,
description:String,
report:String,
pay:Number
},
used:String
}],
});
guildSchema.virtual("addUser").set(function(id){
const user = {
userId:id,
cash:settings.cash,
bank:settings.bank
};
this.users.push(user);
return user;
});
module.exports = model("Servers", guildSchema);
Use findOneAndUpdate
to update the existing document in the collection.
let the object that you want to update in "commands" in mongodb be in x
variable.
Guild.findOneAndUpdate({guildId : serverId},{commands : x));
The object which you have stored in x
variable will directly be updated/replaced with this new data when a match is found.
UPDATE TO NOT COMPLETELY REPLACE EXISTING OBJECT
let guild = Guild.findOne({guildId : serverId});
if(guild){
// guild.commands here will have the existing object.
// Modify it as required and then use findOneAndUpdate again
}
The solution is quite simple. I took it from this site: https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
To give credit:
Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect/save those changes. To "tell" Mongoose that the value of a Mixed type has changed, call the.markModified(path) method of the document passing the path to the Mixed type you just changed.
So, whenever I update the commands (aka whenever I change the access, bounded, or disabled variables), I would use the mark modified method on the command function. My code is:
guildSchema.virtual("saveCommands").set(function(name){
if(["access", "bounded", "disabled"].includes(name)) this.markModified('commands');
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.