How to rename a field in mongoose? - javascript

I have a database in which the schema was originally set as follows;
const productSchema = new mongoose.Schema({
supplier: {
type: String,
required: 'Supplier is required',
ref: 'Supplier'
},
name: {
type: String,
required: 'Name is required'
},
price: {
type: Number,
required: 'Price is required'
}
})
But now I want to rename the field name to product like so;
const productSchema = new mongoose.Schema({
supplier: {
type: String,
required: 'Supplier is required',
ref: 'Supplier'
},
product: {
type: String,
required: 'Product is required'
},
price: {
type: Number,
required: 'Price is required'
}
})
The result I am getting from my client isn't updating to show the product instead of name;
Result:
[
{
"_id": "5df7baa7acf4ed3897d8d4c9",
"supplier": "Old Co Ltd",
"name": "Small Woggle",
"price": 6
}
]
and finally here is my database where I populate the fields in mongoose;
mongoose.connect(dbURI, (err, db) => {
db.dropDatabase()
.then(() => Product.create([{
supplier: 'Old Co Ltd',
product: 'Small Woggle',
price: 6
}]))
.then(products => console.log(`${products.length} products created`))
.catch(err => console.log(err))
.finally(() => mongoose.connection.close())
})
Please help me to rename this field

You can't just rename the field in your schema. You need to actually run an update.
Example:
productSchema.update({}, { $rename: { name: 'product' } }, { multi: true }, (err) => {
if(err) { throw err; }
console.log('complete');
});
https://docs.mongodb.com/manual/reference/operator/update/rename/

The answer above works, but I also found an alternative without adding anything to your code.
Just use the following steps like so;
1. In terminal run mongod
2. Navigate to db and drop database db.dropDatabase()
3. Then initialize your database by running node on the file.

Related

Mongoose populate returns an empty array | multiple levels of embedded documents

I am trying to populate my ChatRoom model with the User reference. However, it returns a ChatRoom object with only _ids where I expected usernames, as if I never applied populate on it.
Here is an extract of my ChatRoom model :
const ChatRoom = mongoose.model("ChatRoom", {
sender: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
roomname: { type: String, default: "new room" },
messages: [
{
messages: {
type: mongoose.Schema.Types.ObjectId,
ref: "Message",
},
meta: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
delivered: Boolean,
read: Boolean,
},
],
},
],
participants: [
{
user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
},
],
isPrivate: { type: Boolean, default: "false" },
});
My User model :
const User = mongoose.model("User", {
username: { required: true, unique: true, type: String },
avatar: Object,
token: String,
hash: String,
salt: String,
chatroom: {
type: mongoose.Schema.Types.ObjectId,
ref: "ChatRoom",
},
});
As this seems to be a recurrent issue, I tested several StackOverflow answers for my populate code :
Using populate('participants.user') and 'model: user' or just populate('participants.user'), same solution here:
const chatroom = await ChatRoom.findById(req.params.id)
.populate([
{
path: "participants.user",
model: "User",
},
])
.exec((err, user) => {
if (err) {
console.log("error", err);
} else {
console.log("Populated User " + user);
}
});
The console.log returns :
Populated User { _id: new ObjectId("62262b342e28298eb438d9eb"),
sender: new ObjectId("6225d86c9340237fe2a3f067"), roomname:
'Hosmeade', participants: [ { _id: new
ObjectId("6225d86c9340237fe2a3f067") } ], isPrivate: false,
messages: [], __v: 0 }
As if no populate method was ever applied. On the client side, I get an empty string.
Checking my documents aren't empty, this link mentions that Mongoose get problems with detecting referring model across multiple files but the solution doesn't work for me :
_id:6225d86c9340237fe2a3f067 username:"Berlioz" token:"rTCLAiU7jq3Smi3B"
hash:"wvJdqq25jYSaJjfiHAV4YRn/Yub+s1KHXzGrkDpaPus="
salt:"hZdiqIQQXGM1ryYK" avatar:Object
__v:0
If I remove the .exec(...) part, I get the info on the client side, but participants is still filled with only id :
chatroom response : Object { _id: "62262bb14e66d86fb8a041e8",
sender: "6225d86c9340237fe2a3f067", roomname: "Very secret room",
participants: (1) […], isPrivate: false, messages: [], __v: 0 }
I also tried with select: 'username' and get the same result as above :
const chatroom = await ChatRoom.findById(req.params.id).populate({
path: "participants.user",
select: "username",
});
Populating it "as an array"
Changing type of participants.user in my ChatRoom model into an Object (nothing changes)
If needed hereafter are my repos:
Client side and Backend
I run out of ideas on how to debbug my code. Any help would be great !

Save array of ObjectId's using Mongoose's Schema

I have a Mongoose Schema like:
const Role = new Schema({
guildID: {
type: Schema.Types.ObjectId,
ref: 'guilds',
required: true
},
roles: {
owner: {
id: {
type: Number,
required: false
},
commands: [[Schema.Types.ObjectId]]
}
}
})
And a small function to test whether it saves the data as desired which contains:
const roleTest = new Role({
guildID: "61a679e18d84bff40c2f88fd",
roles: {
owner: {
id: 123456789
},
commands: [
"61af57d828b9fd5a07dbdcba",
"61af5a6728b9fd5a07dbdcbb",
"61af5ab728b9fd5a07dbdcbc"
]
}
})
roleTest.save((err, doc) => {
if (err) return res.sendStatus(500)
console.log('Done')
})
It saves everything correctly except the array ObjectIds (commands). What is going wrong here?
You've written the commands in schema with nested array. Try with single array:
{
commands: [Schema.Types.ObjectId],
}
Try this:
commands: [
{ type: mongoose.Schema.Types.ObjectId }
]

How do I specify options for commands?

I want to specify choices for an option for my command in Discord.js. How do I do that?
The command:
module.exports = {
name: 'gifsearch',
description: 'Returns a gif based on your search term.',
options: [{
name: 'type',
type: 'STRING',
description: 'Whether to search for gifs or stickers.',
choices: //***this is the area where I have a question***
required: true
},
{
name: 'search_term',
type: 'STRING',
description: 'The search term to use when searching for gifs.',
required: true,
}],
async execute(interaction) {
let searchTerm = interaction.options.getString('search_term')
const res = fetch(`https://api.giphy.com/v1/gifs/search?q=${searchTerm}&api_key=${process.env.giphyAPIkey}&limit=1&rating=g`)
.then((res) => res.json())
.then((json) => {
if (json.data.length <= 0) return interaction.reply({ content: `No gifs found!` })
interaction.reply({content: `${json.data[0].url}`})
})
},
};
I have read the discord.js documentation/guide and I know about the .addChoice() method, but it doesn't look like that will be compatible with my bot's current code.
The discord.js api describes this as ApplicationCommandOptionChoices.
So you basically just insert an array of this in your choices.
module.exports = {
...
choices: [
{
name: "name to display",
value: "the actual value"
},
{
name: "another option",
value: "the other value"
}
]
...
};

Checking if a user has a certain role

So I use mongoDb in my express server and store the user information like this:
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true },
email: {type: String, required: true , index: { unique: true } },
isActive: {type:Boolean, default:false},
signUpDate: {type: Date, default: Date.now()},
roles: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Role"
}
]
});
With Role having a simple single field : name.
To find out if a user is an admin for example I do:
User.findById(req.SecureUserId).populate('roles').exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for(let roles of user.roles){
if(roles.name === 'admin'){
next();
return;
}
}
However, this seems like something I can better query to my database ?
How would I do this in mongoDB?
You can use .aggregate() to "join" single user with his role and then run $match to verify if there's any role named admin. If particular user doesn't have such role then aggregation will return an empty array:
User.aggregate([
{ $match: { _id: req.SecureUserId } },
{
$lookup: {
from: "roles",
localField: "roles",
foreignField: "_id",
as: "roles"
}
},
{ $match: { "roles.name": "admin" } }
]).exec((err, user) => {
if(user.length === 1){
next();
}
})

Mongo populate in optional field giving cast error

I have a 'vendor' and 'media' collection, media collection store vendor profile images and that is not mandatory field for vendors. Some vendors have profile picture some not, I want to list all vendors including their profile pictures reference. But I'm getting cast error when I populate profilePicture from meidas. I have other populate like 'userId', 'venueId' those are mandatory fields and it works.
Error:
CastError: Cast to ObjectId failed for value "xyz" at path "_id" for model "medias" undefined
Find Query:
const result = await resultObject.skip(skip)
.populate('userId')
.populate('venueId')
.populate('profilePicture')
.limit(parseInt(obj.pageSize, 10))
.sort({ [obj.sortColumn]: parseInt(obj.sortValue, 10) });
return result;
medias model
const MediasModel = () => {
const MediasSchema = new mongoose.Schema({
url: { type: String, required: true },
key: { type: String},
}, { timestamps: { createdAt: 'createdDate', updatedAt: 'modifedDate' } });
return mongoose.model('medias', MediasSchema);
};
module.exports = MediasModel();
vendors model
const Vendors = new mongoose.Schema({
venueId: { type: mongoose.Schema.Types.ObjectId, ref: 'venues' },
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'users' },
name: { type: String, required: true },
profilePicture: { type: mongoose.Schema.Types.ObjectId, ref: 'medias' },
}, { timestamps: { createdAt: 'createdDate', updatedAt: 'modifedDate' } });
module.exports = mongoose.model('vendors', Vendors);
Try the below code
const Vendors = require('path/to/model_vendor');
Vendors.find()
.populate([{path: 'venues'}, {path: 'users'}, {path: 'medias'}])
.skip(skip_value)
.limit(limit_value)
.sort({condition: 1 }) // Modify according to your need
.exec().
.then(vendors=>{
console.log(vendors)
}).catch(err=>{
console.log(err)
})

Categories

Resources