how to add comments to mongoose array with node and reactjs? - node.js

So I am running into an issue trying to add comments to some data that is already in my mongoDB database. I want to make it so I can have comments be added and removed and updated for each account saved in my database and I am not sure what I am doing wrong necessarily. I have set up my front end to send in a new comment and all the data that needs to come along with it. it successfully gets to my back end, and at my backend it says it runs through and it gets saved but it doesnt, and when i reload the page the comments array in my data is still 0.
Account.findByIdAndUpdate(
{ _id: comment.accountId },
{
$push: {Account: { comments: comment }},
},
{ new: true, upsert: true }
).exec(function (err, task) {
if (err) {
return res
.status(400)
.send({ message: "Failed to add comment due to invalid params" });
}
console.log("successfully uploaded comment");
return res.status(200).send(task);
});
so here we are loading the specific account and then pushing that new comment to the comments array that is in my mongoose schema. when I take out the "Account: object and just ahve the object with comments:comment, it says there is an internal error on the back end not finding the parameter i guess, which would be comments array.
I dont know why that would be an issue. below is my mongoose schema as well.
const AccountSchema = new Schema({
username: {
type: String,
},
name: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
description: {
type: String,
},
latitude: {
type: Number,
},
longitude: {
type: Number,
},
comments: [
{
id: Number,
text: String,
type: String,
date: Date,
replies: [{ id: Number, text: String, type: String, date: Date }],
},
],
});
Am I not setting up my schema correctly? or am I forgetting to add something somewhere. any help would be great, thank you!

It looks like your update query's $push specification is to blame. In the code, it says:
$push: {Account: { comments: comment }}
But your Account model does not have an "Account" field to push an object into. To insert a new element into the "comments" array, do this instead:
$push: { comments: comment }

Just wanted to post an update, I changed around the options on the findbyidandupdate, i added new and safe and upsert all true, and then low and behold I realized that my main issue was that my comments array in my schema was set to type: string, and not array. lol thanks for the help guys.

Related

MongoDB ailed to create product document

I hope this is the right place to discuss the CRUD issues. So I'm building a MERN e-commerce app, where I created the mongoose schema and connected with MongoDB to store the products & users. To test my schema and routes I used Postman, and while other requests related to users were working as usual I faced a weird error in the case of adding new products since this is the most important feature.
I'm not sure what is this error and why is this error occurring.
This is my POST request body -
const Product = require("../models/Product");
const router = require("express").Router();
// CREATE PRODUCT
router.post("/", verifyTokenAndAdmin, async (req, res) => {
const newProduct = new Product(req.body);
try {
const savedProduct = await newProduct.save();
res.status(200).json(savedProduct);
} catch (err) {
res.status(500).json(err);
}
});
The verifyToken is a JWT token.
Here is the Schema
const mongoose = require("mongoose");
const ProductSchema = new mongoose.Schema(
{
prodId: {
type: String,
required: true,
},
prodName: {
type: String,
required: true,
},
brandName: {
type: String,
required: true,
},
img: {
type: Array,
},
color: {
type: Array,
},
size: {
type: Object,
},
fabricSpecs: {
type: String,
},
model: {
type: String,
},
descDetail: {
type: String,
},
price: {
type: Number,
required: true
},
discount: {
type: Boolean
},
discountAmount: {
type: Number
},
rating: {
type: String
},
review: {
type: Number
},
soldOut: {
type: Boolean
},
category: {
type: String,
},
type: {
type: String,
}
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Product", ProductSchema);
Here is the error shown in the Postman while adding creating another product
Tried mongo shell also but getting the same error
The error indicates an entry with {title: null} already exists for the index title_1. It is most likely a unique index and you need to adjust the title if entry item is a variant under the same title.
I am really grateful to Doug Duncan from the MongoDB community who helped me in figuring out the problem.
So the actual issue as described by Dough was that apparently, I was having a title field with a unique index that was being populated every time I was inserting a new document. Now for the first index, everything was fine and the document got inserted successfully but after that, all the inserts were throwing this title field null error shown below:
What I am seeing is that you have a unique index on the title field for the products collection. This is not getting populated so a null value is getting passed to the document and there is already a document with a null value in the collection. You have a unique index on the title based on the error you’re getting. Run db.products.getIndexes() and you should see the index.
Ironically, I haven't inserted any field named "title" anytime in my product schema, so how does this happen?
It turns out that MongoDB will allow you to create indexes on fields that don’t exist. It seems that somehow a unique index got created on the title field at some time even though no documents would contain that field. Now this can be fixed by dropping that index everything should be good and you will be able to insert more than a single document without the duplicate key violation.
So I ran the db.products.getIndexes() command in the mongo shell and found that he was right, there was actually a "title" field with a unique index value.
According to Dough, this can be fixed by removing the title field using this command
db.products.dropIndex({"title": 1})
Thanks to Dough, after running this command I can insert multiple documents since the title field is removed now and the only unique index is productId, which I make sure is always unique during insertion.
More about dropIndex -
https://www.mongodb.com/docs/v4.4/reference/method/db.collection.dropIndex/?_ga=2.253559119.714913216.1662801611-1986988651.1652705652

Using DELETE Rest api to remove array object from Mongodb

I am using Node.js, express, mongodb, and mongoose. I have two files: favorite and favorite-route.
"favorites" in the schema has multiple objects in it array. Given the mongodb assigned _id, I would like to create a delete method to gremove the specified object in the array.
Here is my schema in favorite:
userID:{
//type: String,
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: true,
unique: true
},
favorites:[{
publication: {
type:mongoose.Schema.Types.ObjectId,
ref: "Pet"
},
id: {
type: String,
required: true
},
comment: {
type: String,
required: true
}
}]
})
favoritesSchema.statics.deleteFavorite = async (favID)=>{
return await Favorite.findOneAndUpdate({favID})
}
This is my delete method in favorite-route file:
router.delete('/:favID', async (req,res)=>{
let doc = await Favorite.deleteFavorite(req.params.favID)
if(doc){
doc.splice(req.params.favID);
res.send(doc)
return;
}
res.status(404).send({error: "no se encontró esa publicación"})
})
And lastly, here is my http:
DELETE {{host}}/api/favorites/626eddd14762eb4ae4c77f9e
When i test this, it gives me the error:
TypeError: doc.splice is not a function
I'd appreciate any tips and insight. I have spent a while searching for answers but most suggested using $pull, which I am unsure how to implement in the delete method.
Thank you :)
you should do.
Favorite.updateOne(
{ userID: user._id }, // this is the query to find the desired favourite list
{ $pull: { favorites: { id : req.params.favID }} }, // this removes
);

Insert a document with mongoose without initialize the model with empty attributes

I want to insert a document in my database from a website form. I have a model created with mongoose and I want to save in the database only the attributes that contains data and I don't want to save empty attributes.
This is my model:
const localizationSchema = new Schema({
name: { type: String, required: true },
spins: [{ type: String }],
spinsForChild: [{ type: String }],
parent: { id: String, name: String },
localizationType: { type: String },
count: { type: Number, default: 0 },
countries: [{ id: String, name: String, cities: [{ id: String, name: String }] }]
});
const Localization = mongoose.model('Localization', localizationSchema);
When I try to save a new document, it creates in the database all attributes although I don't send it on my query.
Localization.create({
name: body.name,
localizationType: body.localizationType,
"parent.id": parent.id,
"parent.name": parent.name,
spins: spins,
spinsForChild: spinsForChild
}, function(err) {
if (err) return handleError(err);
res.redirect('/localizations');
});
This code, for example, inserts in the DB an empty array called "countries".
I tried to use strict: false in the model declaration but it didn't works.
You could use this answer.
But, thing you try to implement seems to be anti-pattern and can cause errors when you will try to use array update operators with undefined array. So, use it carefully.
Good luck!

How to implement an upvote/downvote system in MongoDB/Mongoose?

I am new to MongoDB, and I'm trying to implement an upvote/downvote system so that users can vote on reviews in my application.
How I've set up my system is that the user sends an POST request via AJAX by pressing an upvote or downvote button in the application, which contains a boolean "upvote" which is an upvote if true, and a downvote if false (this code works so I didn't include it). Once the request reaches the server, the server checks if the review the user voted on contains a vote already. If not, the server adds a vote to the review's "votes" array and increments or decrements the voteBalance attribute of that review. If there already exists a vote in that review's "votes" array then it should either:
1) Modify it if the existing vote's upvote attribute is different from the new vote and then modify voteBalance accordingly, or
2) Delete the existing vote if its upvote attribute is the same as the new one and then modify voteBalance accordingly
My code for inserting a new vote works fine, but the issue I'm having is that I can't figure out how to make it work when a vote already exists. In the server-side code below, the else statement near the bottom is what I tried to handle case 1) from above, but it doesn't work. So how can I get both these cases to work?
Here is my Review schema:
var ReviewSchema = new mongoose.Schema({
authorID: {
type: String,
required: true,
},
movieID: {
type: Number,
required: true,
},
date: {
type: Number,
required: true
},
username: {
type: String,
required: true
},
score: {
type: Number,
required: true
},
text: {
type: String
},
voteBalance: {
type: Number,
required: true,
default: 0
},
votes: [{
voterID: {
type: String,
required: true,
},
upvote: {
type: Boolean,
required: true
}
}],
comments: [{
commenterID: {
type: String,
required: true,
},
text: {
type: String,
required: true
},
date: {
type: Number,
required: true
}
}]
},{collection: 'reviews'});
Here is the code I'm using to create and update votes on the server:
Review.findOne({_id: new ObjectID(reviewID), votes: { $elemMatch: { voterID: req.session._id }}}, function(err, review) {
if (err) {
console.log(err);
res.status(500).send();
}
//If vote was not found (or if review was not found), create vote
if (!review) {
if (upvote) {
var update = {$addToSet: {votes: {voterID: req.session._id, upvote}}, $inc : {voteBalance : 1}};
}
else {
var update = {$addToSet: {votes: {voterID: req.session._id, upvote}}, $inc : {voteBalance : -1}};
}
Review.findOneAndUpdate({_id: new ObjectID(reviewID)}, update, function(err, review) {
if (err) {
console.log(err);
return res.status(500).send();
}
res.status(200).send();
});
}
//If vote was found, update
else {
if (upvote) {
var update = {$set: { 'votes.$.upvote': upvote }, $inc : {voteBalance : 1}};
}
else {
var update = {$set: { 'votes.$.upvote': upvote }, $inc : {voteBalance : -1}};
}
Review.findOneAndUpdate({_id: new ObjectID(reviewID), 'votes.$.voterID': req.session._id}, update, function(err) {
if (err) {
console.log(err);
return res.status(500).send();
}
res.status(200).send();
});
}
});
Also, I recognize that this code is probably not as efficient as it could be, and I would appreciate any tips on that front as well.
Instead of doing findOne() and then findOneAndUpdate(), you would be better off using findOneAndUpdate() with the upsert option. That way you don't need that extra if statement in the callback.
I'd also recommend not storing votes as an array in the ReviewSchema. That array can grow without bound because any number of users can vote on a Review, which means a review document might become huge and unwieldy. I'd recommend using a mapping collection instead.

How to not save a certain field in Mongoose?

I am updating a record via Mongoose but when I try to not include a field by not including it in the properties object the field just gets set to empty.
My model:
var demo = new Schema({
name: String,
slug: String,
code: String,
details: String,
scripts: [],
css: [],
status: {
type: String,
default: "draft"
},
lastModifiedDate: {
type: Date,
default: Date.now
},
projectId: Schema.ObjectId
});
Where I'm saving:
Demo.find({ slug: req.params.demoSlug }, function(err,demos){
if(err){
console.log("Error retrieving demo from db");
res.send(500,err);
return;
}
demos[0].update({ _id:req.params.id },{
name: data.demoName,
slug: Utils.createSlug(data.demoName),
// code: data.demoCode,
details: data.demoDetails
}, someCallback);
});
As you can see the "code" field is commented out so why is the field value being overridden? Are there any flags I need to set when
It's not clear exactly what you're trying to do. You're searching for every document in a collection, but you're only updating one of them, which you're finding by _id. This looks like it can be done in one function, and you could be getting an error because you're calling update on a model that you returned. It looks like you should have written it like this:
Demo.update({ _id:req.params.id },{
name: data.demoName,
slug: Utils.createSlug(data.demoName),
// code: data.demoCode,
details: data.demoDetails
}, someCallback);
If you only want to update the document if its slug matches your demoSlug AND the _id matches, it would look like this:
Demo.update({ _id: req.params.id, slug: req.params.demoSlug },{
name: data.demoName,
slug: Utils.createSlug(data.demoName),
// code: data.demoCode,
details: data.demoDetails
}, someCallback);
If this still doesn't address your problem, hopefully it helps you explain more clearly what exactly you're looking for.
EDIT:
Another way to do this would be to use findOne and save. Try this:
Demo.findOne({ slug: req.params.demoSlug }, function(err, demo) {
if(err) {
console.log("Error retrieving demo from db");
res.send(500, err);
return;
}
demo.name = data.demoName;
demo.slug = Utils.createSlug(data.demoName);
demo.details = data.demoDetails;
demo.save(callback);
}
Something like that should hopefully work. If neither of these work, I suspect that the problem is in data or in the document you're finding.

Resources