I want to create a complex nested document which can store values like this
category: {
"fish": ["Sardines", "Goldfish"],
"dogs": ["German Shepherd", "Dobberman"]
}
Here's what I tried
export const CategorySchema = new mongoose.Schema(
{
category: {
type: Map,
of: [String],
},
},
{ timestamps: true }
);
I passed data like this (from console)
this is how the passed data looks like
Nothing is being created in the database. Also no error.
export default async (req, res) => {
const { method } = req;
switch (method) {
case "GET":
try {
const categories = await Category.find({});
res.json({ success: true, data: categories });
} catch (error) {
res.json({ success: false });
}
break;
case "POST":
try {
let data = req.body;
data = JSON.parse(data);
const category = new Category(data);
const doc = await category.save();
console.log("Doc from Categories API", doc);
res.json({ success: true, data: doc });
} catch (error) {
res.json({ success: false });
}
break;
default:
res.status(400).json({ success: false });
break;
}
};
Can anyone advise me, please?
Related
I have two models, defined in two seperate files
//models/Projects.js
const mongoose = require('mongoose');
export const projectSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
companyBackground: {
type: String,
required: false,
trim: true,
}
});
module.exports = mongoose.models.Project || mongoose.model('Project', projectSchema);
//models/User.js
const mongoose = require('mongoose');
const { projectSchema } = require('./Project');
const userSchema = new mongoose.Schema({
projects: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Project' }]
});
module.exports = mongoose.models.User || mongoose.model('User', userSchema);
I create a new user, and then create a new project, by pushing it to the user
import dbConnect from "utils/dbConnect";
import User from "models/User";
import Project from "models/Project";
export default async (req, res) => {
await dbConnect();
const { query: { id }, method } = req;
switch (method) {
case "POST":
try {
const user = await User.findById(id);
if (!user) {
return res.status(400).json({ success: false, message: "User not found" });
}
const newProject = new Project(req.body);
console.log(newProject);
user.projects.push(newProject);
await user.save();
if (!user) {
return res.status(400).json({ success: false, message: "Project not added"
}
res.status(200).json({ data: user });
} catch (error) {
res.status(400).json({ success: false, message: error.message });
}
break;
default:
res.status(400).json({ success: false });
break;
}
};
Bu here is the question. I can easily create a new project and save it to the user, but not make any updates.
Approaches I have tried include (but are not limited to):
https://stackoverflow.com/a/26157458/2947684
https://stackoverflow.com/a/47762417/2947684
To demonstrate the problems, see
const updateString = "projects.$." + req.body.property;
Project.findOneAndUpdate(
{ _id: req.body.projectid },
{ $set: { [updateString]: req.body.value } },
function (error, success) {
if (error) {
console.log('error');
console.log(error);
} else {
console.log("success");
console.log(success); //Returns null
}
}
);
The above returns null
And when I do this, I get
User.findById(userid)
.then((user => {
const project = user.projects.id(req.body.projectid); //user.projects.id is not a function
project.set(newContent);
return user.save();
}))
.then((user) => {
res.send(user);
})
.catch((error) => {
console.log('error: ', error.message);
res.status(400).json({ success: false, message: error.message });
});
Here is says that user.projects.id is not a function...
In mongo DB Atlas, I can see that the project has indeed been created.
This is turning me crazy, can someone tell me what I am doing wrong?
Would it be better, simply to create the projects as arrays (without making them as a mongoose object?)
When pushing to user.projects you should just add the _id since the property is defined as ObjectId[]:
try {
const user = await User.findById(id);
if (!user) {
return res.status(400).json({ success: false, message: 'User not found' });
}
const newProject = await Project.create(req.body);
console.log(newProject);
user.projects.push(newProject._id);
await user.save();
if (!user) {
return res
.status(400)
.json({ success: false, message: 'Project not added' });
}
res.status(200).json({ data: user });
} catch (error) {
res.status(400).json({ success: false, message: error.message });
}
Then, to update a Project you can simply do:
Project.findByIdAndUpdate(
req.body.projectid,
{ $set: { [req.body.property]: req.body.value } },
{ new: true }, // returns updated doc
function (error, success) {
if (error) {
console.log('error');
console.log(error);
} else {
console.log("success");
console.log(success); //Returns null
}
}
);
i am working on a mern project where i need to create an agenda that contains an attribute as array of appointments types.
in the nodejs api i am declaring a var typeRefs = [];
if a type is present in the types model i insert its ref in the previous array else i create the type and insert the new type ref in the previous array, finally i create the agenda doc based on the typeRefs array, but the array is empty outside the map function scope , inside the map function scope i can see the array values changing.
//agenda model
const agendaSchema = mongoose.Schema(
{
name: String,
types: [{ type: mongoose.Schema.Types.ObjectId, ref: "Type" }],
establishment: {
type: mongoose.Schema.Types.ObjectId,
ref: "Establishment",
},
template: { type: mongoose.Schema.Types.ObjectId, ref: "Template" },
isActive: { type: Boolean, default: true },
},
{ timestamps: true }
);
var Agenda = mongoose.model("Agenda", agendaSchema);
export default Agenda;
// types model
import mongoose from "mongoose";
const typeSchema = mongoose.Schema(
{
name: String,
duration: Number,
color: String,
online: { type: Boolean, default: true },
establishment: {
type: mongoose.Schema.Types.ObjectId,
ref: "Establishment",
},
},
{ timestamps: true }
);
var Type = mongoose.model("Type", typeSchema);
export default Type;
// api function for agenda creation
export const add = async (req, res) => {
var data = req.body;
try {
var typesRefs = [];
data.types.map((type) => {
Type.find({ name: type.text.toUpperCase() }, (err, res) => {
if (res.length === 0) {
const newType = new Type({
name: type.text.toUpperCase(),
establishment: data.establishment,
});
newType.save();
typesRefs = [...typesRefs, newType._id];
} else {
typesRefs = [...typesRefs, type._id];
}
});
});
console.log(typesRefs);
await Agenda.create({ ...data, types: typesRefs });
res.status(200).json({ message: "Agenda created successfully" });
} catch (error) {
console.log(error);
res.status(401).json({ message: "An error occured !" });
}
};
the trick is to use a for loop instead of map function.
export const add = async (req, res) => {
var data = req.body;
var typeRefs = [];
try {
for (let i = 0; i < data.types.length; i++) {
const typeExist = await Type.find({
name: data.types[i].text.toUpperCase(),
});
if (typeExist.length === 0) {
const newType = await Type.create({
name: data.types[i].text.toUpperCase(),
establishment: data.establishment,
});
typeRefs = [...typeRefs, newType._id];
} else {
typeRefs = [...typeRefs, data.types[i]._id];
}
}
console.log(typeRefs);
await Agenda.create({ ...data, types: typeRefs });
res.status(200).json({ message: "Agenda created successfully" });
} catch (error) {
console.log(error);
res.status(401).json({ message: "An error occured !" });
}
};
updateProfile: async function(req, res) {
try {
const update = req.body;
const id = req.params.id;
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
const image = req.files.profileImage;
const cloudFile = await upload(image.tempFilePath);
const profileImage = cloudFile.url
console.log('Loging cloudfile', profileImage)
await User.updateOne(id, { update }, { profileImage }, { new: true },
function(err, doc) {
if (err) {
console.log(err)
}
if (doc) {
return res.status(200).send({ sucess: true, msg: 'Profile updated successful' })
}
});
} catch (error) {
res.status(500).json({ msg: error.message });
}
}
But I'm getting an error of "Callback must be a function, got [object Object]"
I have tried to $set: update and $set: profileImage but still not working.
So the image successful upload into the cloudinary but the update for mongoose is not working.
Upon brief research into the issue, I think you are feeding the arguments in wrong. Objects can be confusing but not to worry.
Your code is:
await User.updateOne(id, { update }, { profileImage }, { new: true }
However, I believe it should be something more like:
await User.updateOne({id: id}, { profileImagine: profileImage, new: true },
The API reference annotates use of the function as:
const filter = { name: 'John Doe' };
const update = { age: 30 };
const oldDocument = await User.updateOne(filter, update);
oldDocument.n; // Number of documents matched
oldDocument.nModified; // Number of documents modified
I'm new to MongoDB. I have a DB where cards data will be stored and update counts if the user likes the cards. Giving me a total likes number.
I keep getting my res as a 400 and I can't work out why. I got the update method to work manually. but when I put it into a function it does not work.
I'm using NEXT JS API routes.
import dbConnect from "../../utils/dbConnect";
import FavSchema from "../../models/FavoriteModel";
dbConnect();
export default async (req, res) => {
const { method } = req;
switch (method) {
case "GET":
try {
} catch (error) {
res.status(400).json({ success: false });
}
break;
case "POST":
try {
const query = {
cardId: req.body.cardHandler,
};
await FavSchema.findOneAndUpdate(
query,
{ $inc: { favCount: 1 } },
{ upsert: true }
);
res.send("Succesfully saved.");
} catch (error) {
res.send(400, { error: "Error" });
}
}
};
function
const handleCardFavClick = (id) => {
const cardHandler = {
id,
};
fetch("/api/favcounter", {
method: "POST",
body: JSON.stringify(cardHandler),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((data) => console.log(data));
dispatch(makeFav(cardHandler));
};
Thank you!
You are passing
{ id: "<id>" }
as body in your API and reading "cardHandler" from req.body, which is "undefined".
In your POST API, replace
const query = {
cardId: req.body.cardHandler,
}
with
const query = {
cardId: req.body.id
}
I can't figure out how to add data to a mongoose sub-document when I create a new schema from the client side. The only data that gets sent over to the data base is the data that is not nested inside another schema/array.
I'm using MongoDB with Mongoose for my database and NextJS as my both my front and back end.
I've haven't been able to find a way to get this working yet. Any help would be appreciated.
This is the back end route:
export default async (req, res) => {
const { method } = req;
switch (method) {
case "POST":
try {
const workout = req.body;
const newWorkout = new Workout({ ...workout });
await newWorkout.save();
res.status(201).json({ success: true, data: newWorkout });
} catch (error) {
res.status(400).json({ success: false });
}
break;
This is the mongoose schema:
import mongoose from "mongoose";
const reqString = {
type: String,
required: true,
};
const WodSchema = new mongoose.Schema({
exerciseName: reqString,
repCount: reqString,
});
const exerciseSchema = new mongoose.Schema({
workoutName: String,
workoutContent: [WodSchema],
});
const WorkoutSchema = new mongoose.Schema({
name: { type: String },
workout: [exerciseSchema],
// timestamps: true,
});
module.exports =
mongoose.models.Workout || mongoose.model("Workout", WorkoutSchema);
This is the front end post request (only name gets sent to db):
const [name, setName] = useState("");
const [workoutName, setWorkoutName] = useState("");
const [exerciseName, setExerciseName] = useState("");
const editProgram = async () => {
try {
const res = await fetch(`http://localhost:3000/api/workouts/`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ name, workoutName, exerciseName }),
});
} catch (error) {
console.log(error);
}
};
Solution:
case "POST":
try {
const workout = req.body;
const newWorkout = new Workout({
name: workout.name,
workout: {
workoutName: workout.workoutName,
workoutContent: {
exerciseName: workout.exerciseName,
repCount: workout.repCount,
},
},
});
await newWorkout.save();
res.status(201).json({ success: true, data: newWorkout });
} catch (error) {
res.status(400).json({ success: false });
}