Why will updateOne not work on my schema? - database

This is my current code:
const mongoose = require("mongoose");
const schema = require("../schemas/ecos");
module.exports = async(req, res) => {
const db = await schema.findOne({
RobloxID: req.query.roblox_id
});
if(db.IsPendingVerification === "true") {
res.send({
success: true
})
db.updateOne({
IsNowVerified: "true"
})
}
}
at the moment it will not update the DB so IsNowVerified is true. Why might this be? I do not get any errors.
My Ecos file:
const mongoose = require("mongoose");
const productSchema = mongoose.Schema({
Guild: { type: String, default: "" },
VerifyChannelID: { type: String, default: "" },
VerifyRoleID: { type: String, default: "" },
Prefix: { type: String, default: "v-" },
GuildToken: { type: String, default: "" },
HasGeneratedToken: { type: Number, default: 0 },
VerificationLevel1: { type: Boolean, default: false },
VerificationLevel2: { type: Boolean, default: false },
VerificationLevel3: { type: Boolean, default: false },
VerifcationRBLX: { type: Boolean, default: false },
VerificationRBLXGameLink: { type: Boolean, default: false },
VerifyMessageWelcomeID: { type: String, default: "" },
GuildName: { type: String, default: "" },
GuildInvite: { type: String, default: "" },
UserID: { type: String, default: "" },
RobloxID: { type: String, default: "" },
IsPendingVerification: { type: String, default: "" },
IsNowVerified: { type: String, default: "" }
});
module.exports = mongoose.model("Eco", productSchema, "ecos");
That is the module exports for the ecos of the mongodb database.

Your code is a little confusing, so I've changed some names, but left the functionality the same:
const mongoose = require("mongoose");
const Eco = require("../schemas/ecos");
module.exports = async(req, res) => {
const document = await Eco.findOne({
RobloxID: req.query.roblox_id
});
if(document.IsPendingVerification === "true") {
document.IsNowVerified = "true"
await document.save()
res.send({
success: true
})
}
Now I'll go through the changes:
const Eco = require("../schemas/ecos");
What you are exporting isn't a schema, but the model. The model is the class defining what entries in your database ecos collection look like. You likely have multiple models, so best to name them properly.
const document = await Eco.findOne({
RobloxID: req.query.roblox_id
});
What the findOne query returns is an instance of the Model, representing the document found in the collection. This has all the info in the database document, as well as lots of useful methods to help you modify it.
document.IsNowVerified = "true"
await document.save()
You can directly modify this document, and then save it to the database. This updates the document in database with any changes you made to it.
The updateOne is used directly on the model, for example:
await Eco.updateOne({
RobloxID: req.query.roblox_id
}, {
IsNowVerified = "true"
})
This finds the document by the RobloxId, then updates the fields passed in the second object, in this case IsNowVerified
This is useful as it's a single DB query, so it's quick. But as you want to first check another field, it's better to first find the document and then update it.
Another thing, is to change "true" to true. this will use Boolean in DB rather than string, which takes up much less space, and is the standard practice, which will lead to less errors. But as you're already using the "true" version, changing it will probably cause lots of errors unless you change it everywhere.

Related

Pushing data to an array in already existing object with axios

i have a object which looks like this:
{
"title": "675756",
"release_date": "2022-01-16",
"series": "Better Call Saul",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"characters": [],
"id": 1
}
to an characters array i want to add the id of characters.
I do it by form and then i handle submit like this:
const handleSubmit = (values) => {
console.log("dodano aktora do filmu!");
console.log(values);
addActorToMovie(values);
history.goBack();
};
the addActorToMovie action:
export const addActorToMovie = (resp) => ({
type: types.ADD_CHAR_TO_MOVIE,
payload: resp,
});
and the reducer:
case types.ADD_CHAR_TO_MOVIE:
console.log(action.payload);
return {
...state,
...state.episodes.map(function (item) {
return item.id === action.payload.episodeId
? {
id: item.id,
title: item.title,
release_date: item.release_date,
series: item.series,
img: item.img,
characters: [...item.characters, action.payload.actor],
}
: { ...item };
}),
};
It all works, but the problem is that i dont want to do it loccaly. Im using an database with json-server, and I want to do an Axios Request so that it would add a data to the database.
And i don't know how to do this, when i use axios.post it adds an object to my episodes array, if im using axios.put it changes an object. Is there any possibility to push the data to an array as i do it with the code above, but with axios so that it would be added to database?
My approach looked like this:
export const addActorToMovieAxios = (value) => {
console.log(value);
return async (dispatch) => {
try {
const response = await axios.post(
`http://localhost:3000/episodes/`,
value
);
console.log(response);
dispatch(addActorToMovie(response.data));
} catch (ex) {
console.log(ex);
}
};
};
but as I said this does add a new object to an array.....
"episodes": [
{
"title": "675756",
"release_date": "2022-01-16",
"series": "Better Call Saul",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"characters": [],
"id": 1
},
{
"episodeId": 1,
"actor": "1",
"id": 2
}
]
So just to be clear I understand your question, you have an object that already exists in your DB, and you want to push something onto the 'characters' array in that existing object, without creating a new object, correct?
To do this, I would use Mongo for your DB and define two Mongoose Schemas, one for the existing object (let's call it TVShow) and one for the Characters within that object. Your two Schemas will look like this:
TVShowModel.js:
const mongoose = require('mongoose');
const CharacterModel = require('./CharacterModel')
const TVShowScheme = new mongoose.Schema({
title: {
type: String,
},
release_date: {
type: Date,
},
series: {
type: String,
},
img: {
type: String,
},
characters:[
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Student'
},
],
examQuestions: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'CharacterModel'
}
]
})
module.exports = mongoose.model('TVShowModel', TVShowScheme )
CharacterModel.js:
const mongoose = require('mongoose');
const CharacterModel= new mongoose.Schema({
characterName: {
type: String,
},
actorName: {
type: String,
},
}) // add any other fields you want here
module.exports = mongoose.model('CharacterModel', CharactModelScheme )
Then, create your Axios post request. Make sure you send when you send the 'value' variable to your server, it contains the id (or perhaps the unique title) of the object you'll be 'pushing' to. Push won't work in axios/react, so we'll use the 'spread' opperator instead.
Your router will look like this:
const CharacterModel= require ('../models/CharacterModel');
const TVShowModel= require ('../models/TVShowModel');
const router = express.Router();
router.post('/episodes', async function(req,res){
try{
const tvshow = await TVShowModel.find({title: req.body.title})
// edit as needed
console.log("FOUND TV Show: "+tvshow )
const characterName= req.body.characterName
const actorName = req.body.actorName
const newCharacter = new CharacterModel({
characterName,
actorName,
})
console.log("new character created: "+newCharacter)
tvshow[0].CharacterModel = [...tvshow[0].CharacterModel,newCharacter];
await tvshow[0].save()
.then(()=>res.json('New Character Added to DB'))
.catch(err=>res.status(400).json('Error: ' + err))
} catch(e){
console.log(e)
}
})
Hope this was clear!

Mongoose: TypeError: Invalid value for schema path `guildId.type`, got value "undefined"

I got this error but I don't know what I have done wrong.
My code:
const mongoose = require('mongoose');
const GuildConfigSchema = new mongoose.Schema({
guildId: {
type: mongoose.SchemaType.String,
required: true,
unique: true,
},
prefix: {
type: mongoose.SchemaType.String,
required: true,
default: 'b!',
},
defaultRole: {
type: mongoose.SchemaType.String,
required: false,
},
memberLogChannel: {
type: mongoose.SchemaType.String,
required: false,
},
});
module.exports = mongoose.model('GuildConfig', GuildConfigSchema);
And my guild create event where I am setting the values of the database:
// https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=e-guildCreate
const BaseEvent = require('../utils/structures/BaseEvent');
const GuildConfig = require('../database/schemas/GuildConfig');
module.exports = class GuildCreateEvent extends BaseEvent {
constructor() {
super('guildCreate');
}
async run(client, guild) {
try {
const guildConfig = await GuildConfig.create({
guildId: guild.id,
});
console.log('Successfully joined server!');
} catch(err) {
console.log(err);
}
}
}
My error:
TypeError: Invalid value for schema path `guildId.type`, got value "undefined"
Does anyone see what I've done wrong?
explicitly export GuildConfigSchema
module.exports.GuildConfigSchema = GuildConfigSchema;
and use destructuring where the schema is required.
const { GuildConfigSchema } = require("path to schema file");

CastError: Cast to ObjectId failed for value "{ _id: ':5ec5cc919efcf581eb692690' }" at path "_id" for model "Posts"

Checking the router on the server side it console logs the right values, only the follow error is popping up in here. Trying to build a counter that should update the value on the backend. But the problem I have is that value will not be stored in there. When using Postman the value will be stored successfully. What is the solution that can fix this issue.
export const incrementProduct = (index, updateAmount, id) => {
return dispatch => {
dispatch(increment(index));
try {
axios.patch(`${API_URL}/:${id}`, {
amount: updateAmount
}).then(res => {
console.log(res.config);
})
} catch(err) {
console.log(err)
}
}
}
const PostSchema = mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
editable: {
type: Boolean,
required: true
},
data: {
type: Date,
default: Date.now
}
});
// update
router.patch('/:postId', async(req, res) => {
console.log('update', req.params.postId + 'amount ' + req.body.amount)
try {
const updatedPost = await Post.findByIdAndUpdate(
{_id: req.params.postId}, <--- this cause the console error...
{$set:
{
amount: req.body.amount
},
})
console.log('try')
res.json(updatedPost)
} catch(err) {
console.log(err + 'test ')
res.json({ message: err })
}
})
You need to remove : in the patch url like this:
axios.patch(`${API_URL}/${id}`
Also findByIdAndUpdate requires only the value of _id, so you can only pass the value like this:
await Post.findByIdAndUpdate(req.params.postId, ...
findByIdAndUpdate(id, ...) is equivalent to findOneAndUpdate({ _id: id }, ...).

Sub-document in an array saves as an empty array item if no value is provided on document creation

What I want is for a particular field in my schema to be an array with items in it.
When I create the document in question, I will not have any array items. Therefore, I expect my document to look like:
{
notes: []
}
The problem is, I'm getting an array that looks like:
{
notes: ['']
}
Querying the notes.length, I get 1, which is problematic for me, because it's essentially an empty array item.
This is the code I'm working with:
const SubDocumentSchema = function () {
return new mongoose.Schema({
content: {
type: String,
trim: true
},
date: {
type: Date,
default: Date.now
}
})
}
const DocumentSchema = new mongoose.Schema({
notes: {
type: [SubDocumentSchema()]
}
});
const Document = mongooseConnection.model('DocumentSchema', DocumentSchema)
const t = new Document()
t.save()
You can specify empty array as the default value for notes. And you don't need to return a function for the SubDocumentSchema. Try the below edited code.
const SubDocumentSchema = new mongoose.Schema({
content: {
type: String,
trim: true
},
date: {
type: Date,
default: Date.now
}
})
const DocumentSchema = new mongoose.Schema({
notes: {
type: [SubDocumentSchema],
default: []
}
});
const Document = mongooseConnection.model('DocumentSchema', DocumentSchema)
const t = new Document()
t.save()

Mongoose/Mongo: Update Not Saving

I'm extremely perplexed by this issue that I'm having with mongo/mongoose. I'm essentially trying to get an array of products, delete a certain product from the array, and then update the shopping chart with the new array that omits the selected product. Here's the snippet of code I'm dealing with:
const remove = (req, res, next) => {
console.log('here is the product id ' + req.body.cart.product)
delete req.body._owner // disallow owner reassignment.
Cart.find({_id: req.user.cartId})
.then((products1) => {
console.log("array of products: " + products1[0].product)
const index = products1[0].product.indexOf(req.body.cart.product)
console.log("index valeu: " + index)
if (index > -1) {
products1[0].product.splice(index, 1)
return products1[0].product
}
return products1[0].product
})
.then((products2) => {
console.log('Second Promise Input: ' + products2)
Cart.update({_id: req.user.cartId}, {$set: {product: products2}})
})
.then(() => res.sendStatus(204))
.catch(next)
}
And here's the output from my server:
Server listening on port 4741
here is the product id 5952b57ea52d092b8d34c6b0
array of products: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
index valeu: 0
Second Promise Input: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
PATCH /carts-decrease/595b037e128cfd37e0c864d7 204 38.773 ms
According to my console.logs, I'm getting the array just the way I want it but it simply does not update the shopping cart with the new array. I've been staring at this code for far too long and I'd appreciate a second set of eyes on this. Thanks.
P.S. Ignore the fact that the product ids are all the same, its just a testing variable
Cart Schema:
'use strict'
const mongoose = require('mongoose')
const cartSchema = new mongoose.Schema({
product: {
type: Array,
required: false
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: false
}
}, {
timestamps: true,
toJSON: {
virtuals: true,
transform: function (doc, ret, options) {
const userId = (options.user && options.user._id) || false
ret.editable = userId && userId.equals(doc._owner)
return ret
}
}
})
const Cart = mongoose.model('Cart', cartSchema)
module.exports = Cart
Product Schema:
'use strict'
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
description: {
type: String,
required: true
}
}, {
toJSON: {
virtuals: true
}
})
const Product = mongoose.model('Product', productSchema)
module.exports = Product
Show request:
const show = (req, res) => {
const product = {}
product.array = []
// console.log(req.cart.product)
const promises = []
Promise.all(req.cart.product.map(function (id) {
return Product.find({_id: ObjectId(id)})
})).then(function (products) {
console.log(products)
req.cart.product = products
return res.json({
cart: req.cart.toJSON({virtuals: true, user: req.user})
})
}).catch(function (err) {
console.log(err)
return res.sendStatus(500)
})
}
I would recommend you to slightly modify your cartSchema and store products in the form of an array of embedded documents:
const cartSchema = new mongoose.Schema({
products: [{
name: { type: String },
price: { type: Number }
...
}]
...
});
If you do this you can simply use the $pull update operator to remove products from your cart:
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your case the query should then look like this:
Cart.update(
{ _id: req.user.cartId },
{ $pull: { products: { '_id': req.body.cart.product } }}
);
As the embedded documents will have their own ObjectId there will only be one document matching the query.

Resources