I am trying to add an item to a MongoDB array with RESTAPI through Axios. I thought it would look similar to the push method but I have no idea how to do that.
my Model is of a person:
const Schema = mongoose.Schema;
const PersonSchema = new Schema({
name: String,
password: String,
friends: [],
missions: []
})
const personModel = mongoose.model('Person', PersonSchema);
I want to add a mission to the mission array of a person.
and for example, in order to add a new Person, I use NodeJS and API:
(api.js)
router.post('/api/people', (req, res) => {
const personToAdd = req.body;
const newPersonPost = new personModel(personToAdd);
newPersonPost.save((e) => {
if (e) {
console.log("error");
}
});
res.json({
msg: 'Received'
})
});
and in the client side I use Axios:
axios({
url: 'http://localhost:8080/api/people',
method: 'POST',
data: dataToUpdate
})
.then(() => {
console.log('axios sent info to server');
}).catch((e) => {
console.log('error' + e);
})
Thank you so much!
express
router.post('updating mission endpoint url', async (req, res) =>
try {
const query = { /* content */}; /* write a query to retrieve the concerned user by using a unique identifier */
let person = await personModel.findOne(query);
person.missions.push(req.body.mission);
personModel.save();
} catch (err) {
console.log(err);
}
});
client
In the client side you just have to put the mission you want to add in data like you did above with the right endpoint url and you should add a unique identifier for the user you want to add mission to.
[] will not assign array type to your variable.
Change your schema file with the following:
const Schema = mongoose.Schema;
const PersonSchema = new Schema({
name: { type: String },
password: { type: String },
friends: { type: Array },
missions: { type: Array }
})
Update the db model entity file with following
First method:
const Schema = mongoose.Schema;
const PersonSchema = new Schema({
name: String,
password: String,
friends: {type : Array},
missions: {type : Array}
})
const personModel = mongoose.model('Person', PersonSchema);
Second Method :
const Schema = mongoose.Schema;
const PersonSchema = new Schema({
name: String,
password: String,
friends: [{ type: String }],
missions: [{ type: String }]
})
const personModel = mongoose.model('Person', PersonSchema);
You can update the array object as per your requirements.
You just want to be using the $push update operator, very simple, like so:
db.collection.updateOne(
{
_id: user._id
},
{
"$push": {
"missions": {
mission: newMission
}
}
})
Mongo Playground
Related
Please help me with this one. I have one post query and I want to save it into two tables seperately. But I encountered an error message from postman " Cast to [ObjectId] failed for value "
Please help me! Thank you!
Here is my code below:
FirstModel
const mongoose= require('mongoose');
const { Schema } = mongoose;
const class = require('./classModel');
const SubjectSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
address: {
type: String,
},
classes: [ { type: Schema.Types.ObjectId, ref: class.schema } ]
})
Second Model
const classSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
})
and here is my controller
exports.create = catchAsync (async (req, res, next) => {
const newSubject = await Subject.create(req.body)
let payload = {
body : {
...req.body.classes,
_id: new mongoose.Types.ObjectId(),
golf_course_id: newGolfCourse._id
}
}
const newClass = await Class.createClass(payload)
if(!newClass ) {
res.status(201).json({
status: 'success',
data : {
subject: newSubject
}
})
}
})
It's because you are trying to set your classes in your Subject before they have ObjectIds. In your Subject Schema you have the following line:
classes: [ { type: Schema.Types.ObjectId, ref: class.schema } ]
Which tells Mongoose that you are referencing another model with it's assigned ObjectId but in your case when you try to save it:
await Subject.create(req.body)
These classes don't have ID's yet, so you need to create them. I wouldn't manually set them, when mongoose sets them on it's own. So the following would be a suggestion.
try {
const classes = req.body.classes.map(async (className) => {
const newClass = new Class({ name: className });
newClass.golf_course_id = newGolfCourse._id;
await newClass.save();
return newClass;
});
const results = await Promise.all(classes);
const newSubject = await new Subject({
name: req.body.name,
address: req.body.address,
classes: results,
});
res.send(newSubject);
} catch (error) {
console.log(error);
}
This method creates the classes just like you had in your code but then it give the classes to the Subject after they have been created, that way the Subject can use them. Otherwise you will get an ObjectId error because you can't assign a field with a reference e.g. classes: [ { type: Schema.Types.ObjectId, ref: class.schema } ] without a reference to that item. By the way in your ref: class.schema just use ref: 'Class'
This is my table schema
var mongoose=require("mongoose");
var tableSchema=new mongoose.Schema({
tName:String,
keys:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"key"
}
],
fields:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"field"
}
]
})
module.exports=mongoose.model("table",tableSchema);
----Key Schema
var mongoose=require("mongoose")
var keySchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("key",keySchema);
---field Schema
var mongoose=require("mongoose")
var fieldSchema=new mongoose.Schema({
name:[String],
value:[String]
})
module.exports=mongoose.model("field",fieldSchema);
----How I Pushed into
app.post("/table/:id/value",function(req,res){
var Key={
name:req.body.key,
value:req.body.keyValue
}
var Field={
name:req.body.field,
value:req.body.fieldValue
}
table.findById(req.params.id,function(err,foundTable){
if(err){
console.log(err)
}
else{
console.log(foundTable)
key.create(Key,function(err,createKey){
foundTable.keys.push(createKey)
console.log(createKey)
})
field.create(Field,function(err,createField){
foundTable.fields.push(createField)
console.log(createField)
})
foundTable.save();
console.log(foundTable);
res.redirect("/table/"+req.params.id)
}
})
})
ObjectId are not being refernced
Here is the Image that prints the table
How I populated the table
app.get("/table/:id",function(req,res){
table.findById(req.params.id).populate("keys").populate("fields").exec(function(err,foundTable){
if(err){
console.log(err)
res.redirect("/")
}
else{
console.log(foundTable);
res.render("show",{table:foundTable})
}
})
})
I Dont know where I had gone wrong,
everything seems to be fine but
the objected is not referenced when printed and
it is not being populated
How it should be printed reference: https://bezkoder.com/mongoose-one-to-one-relationship-example/
This is an example:
1st schema
const mongoose = require("mongoose");
const Customer = mongoose.model(
"Customer",
new mongoose.Schema({
name: String,
age: Number,
gender: String
})
);
module.exports = Customer;
2nd schema
const mongoose = require("mongoose");
const Identifier = mongoose.model(
"Identifier",
new mongoose.Schema({
cardCode: String,
customer: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer"
}
})
);
module.exports = Identifier;
How it should be printed
{
_id : ObjectId("5da000be062dc522eccaedeb"),
cardCode : "5DA000BC06",
customer : ObjectId("5da000bc062dc522eccaedea"),
__v : 0
}
How it should be populated
[ { _id: 5da135bf61a1dd3e9c2a6e82,
cardCode: '5DA135BD61',
customer:
{ _id: 5da135bd61a1dd3e9c2a6e81,
name: 'bezkoder',
age: 29,
gender: 'male',
__v: 0 },
__v: 0 } ]
try this .populate([ 'keys', 'fields' ])
The reason why keys and fields are not inserted is that the foundTable.save() will be executed before creating the new Key and Field documents and push there _id to the foundTable.
One way to solve the issue is by using async/await. You can modify your code as below using async/await
app.post("/table/:id/value", async function (req, res) {
var Key = {
name: req.body.key,
value: req.body.keyValue,
};
var Field = {
name: req.body.field,
value: req.body.fieldValue,
};
try {
const foundTable = table.findById(req.params.id);
const createKey = await key.create(Key);
const createField = await field.create(Field);
foundTable.keys.push(createKey._id);
foundTable.fields.push(createField._id);
await await foundTable.save();
res.redirect("/table/"+req.params.id)
} catch (err) {
console.log(err);
// handle failure here
}
});
This will make sure the Key and Field are created and _id is pushed to foundTable before saving the foundTable
Regarding the populate query. Looks like once you save the _id of Field and Key in foundTable your existing query itself should work
In the user model, I have an array of custom objects followedPlaylists which contains two attributes ( playlist: the id of the playlist, public: to determine whether it is public or not) as shown below
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
I want to populate on followedPlaylists.playlist so the response would be something like
[{
playlist: * the actual playlist object *,
public: true
}]
I hope my question is clear enough and thanks in advance.
Here I am assuming that your Playlist is working just fine. i.e., it has elements and has been tested independently.
So, given the schema:
Const Playlist = require (./Playlist)//here you have to provide the path to the Playlist model or use mongoose.model (“Playlist”) to bring it in
………….
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
On whatever you want to print it, just make something like:
Const user = mongoose.model (“User”);//or use require, what fits best your applications
……
Console.log(user.find().populate(“Playlist”))//here is the trick, you ask to populate the Playlist
Example
Examples are the best way to grasp a concept. You can play around with this example:
//------------------------------------------------------------------
const mongoose = require("mongoose");
const { model, Schema } = require("mongoose");
var dbURI = "mongodb://localhost/mongoose-sample";
const app = require("express")();
mongoose
.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(console.log(`connected to ${dbURI}`));
//----------------------------------------------------------------------
const departmentSchema = new Schema({ name: String, location: String });
const Department = model("department", departmentSchema);
const EmployeeSchema = new Schema({
firstName: String,
lastName: String,
department: { type: mongoose.Types.ObjectId, ref: "department" }
});
const Employee = model("employee", EmployeeSchema);
app.use("/", async (req, res) => {
// await Department.remove({});
// await Department.create({
// name: "Fiocruz",
// location: "Presidência"
// }).then(console.log(`we are good`));
// await Department.create({
// name: "IASI",
// location: "Roma"
// }).then(console.log(`we are good`));
// await Employee.create({
// firstName: "Jorge",
// lastName: "Pires",
// department: await Department.findOne({ name: "Fiocruz" })
// });
// await Employee.create({
// firstName: "Marcelo",
// lastName: "Pires",
// department: await Department.findOne({ name: "IASI" })
// });
// Employee.findOne("")
// .populate("department", "name")
// .select("department")
// .then(result => {
// console.log(result);
// });
await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" }, (err, result) => {
console.log(result);
})
.populate("department", "name")
.select("department");
res.json({
departments: await Department.find(),
employees: await Employee.find(),
employeesWithDep: await Employee.find().populate("department", "name"),
justDepartment: await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" })
.populate("department", "name")
.select("department")
});
});
app.listen(3000, () => {
console.log("we are on port 3000");
});
I have an object called company that inside I have name(String) and locations(Array)
Inside locations I want to have a key called name that the user will generate, and second key generated by using ObjectID.
Unfortunately I can't get this to work as expected.
Example from Postman. Note that the locations didn't get _id.
What is going wrong?
My model
const mongoose = require('mongoose')
const companySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: String,
locations: [
{
_id: mongoose.Schema.Types.ObjectId,
name: String
}
]
})
module.exports = mongoose.model('Company', companySchema)
My controller
createCompany: (req, res) => {
const { name, locations } = req.body
const company = new Company({
_id: new mongoose.Types.ObjectId(),
name: name,
locations: locations
})
company
.save()
.then(() => {
res.status(200).json({
company
})
})
.catch(error => {
res.status(500).json({
error
})
})
},
Mongoose will create _id for the top level and nested array of documents itself, which is a default behaviour.
So defining schema with only the fields that you want should be it.
const companySchema = new mongoose.Schema({
name: String,
locations: [
{
name: String
}
]
});
module.exports = mongoose.model("Company", companySchema);
OR
const locationSchema = new mongoose.Schema({
name: String
});
const companySchema = new mongoose.Schema({
name: String,
locations: [locationSchema]
});
module.exports = mongoose.model("Company", companySchema);
And subsequently you don't need to create the _id from the Model object as well.
const company = new Company({
name: name,
locations: locations
});
company
.save()
.then(() => {})
.catch(e => {});
I have a Users model with some fields and reference to "Skills" model.
The models are look like this below
1.Users.js (users model)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UsersSchema = new Scheam({
name: { type : String },
email: { type : String },
address: { type : String },
Skills: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Skills' }],
})
module.exports = mongoose.model('Users', UsersSchema);
2.Skills Model
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const SkillsSchema = new Schema({
name : { type: String },
});
module.exports = mongoose.model('Skills', SkillsSchema);
I am creating the new user with dropdown menu of skills selection storing the id's of the skills in users model.
And getting the skills by populating the Users model like this in node js app.
export function getUser(req, res) {
console.log('getUser');
console.log('req.body',req.body);
Users.findOne({_id: req.body.user_id}).populate('skills').exec(function(err, usr_doc){
if(err) {
res.json({
status: 401,
message: 'something went wrong!',
err: err,
});
} else if (!err && usr_doc != null) {
res.json({
status: 200,
message: 'User details found!',
data: {_id: usr_doc._id, skills: usr_doc.skills,name: usr_doc.name,token: usr_doc.token},
})
}
})//Users.findOne end
}
The above code is working fine for normal rest api.
Here I try to create the Same api using GraphQL server of express-graphql in Nodejs.
The code look like this.
3.Schema.js
const graphql = require('graphql');
const Users = require('../models/Users');
const Skills = require('../models/Skills');
const {
GraphQLObjectType,
GraphQLInt,
GraphQLFloat,
GraphQLString,
GraphQLSchema,
GraphQLID,
GraphQLList,
GraphQLNonNull,
GraphQLBoolean,
GraphQLObject
} = graphql;
const UsersType = new GraphQLObjectType ({
name: 'Users',
fields: () => ({
id: {type: GraphQLID},
name: { type : GraphQLString },
email: { type : GraphQLString },
**skills: {
type: new GraphQLList(SkillsType),
resolve(parent, args){
//Here I need to know how to get the skills name of the users
}
}**
})
const SkillsType = new GraphQLObjectType({
name: 'Skills',
fields: () => ({
name: { type : GraphQLString },
})
})
At present I didn't use any reference id in skills model, only name. I want to get the skill names of the Users.
If i use the below, I am getting all of the skill names instead of user particular or populated skill names.
skills : {
type: new GraphQLList(SkillsType),
resolve(parent, args){
return Skills.find({})
}
Please provide any suggestions regarding this.
I can give more information if you need.
To get the skills of a user, instead of Skills.find({}) which returns all the documents present in the skills collection, add a condition there with the parent object.
The parent object, which contains result from the resolver on the parent field here. So skills, a child resolver, can be written as:
skills: {
type: new GraphQLList(SkillsType),
resolve(parent, args) {
return await Skills.find({"_id": {$in: parent.skills} }) }
}