I have a user model and a car model. One user can have multiple cars. Here is the code -
let UserSchema = new Schema({
name:String,
age:String,
cars:[{
type:Schema.Types.ObjectId,
ref:"Car"
}]
})
const User = mongoose.model("User",UserSchema)
let CarSchema = new Schema({
make:String,
model:String,
owner:{
type:Schema.Types.ObjectId,
ref:"User"
}
})
const Car = mongoose.model("Car",CarSchema)
I am creating a user and a car model and storing the user id in the car and vice versa like this -
const user = new User({
_id: new mongoose.Types.ObjectId(),
name:'Raj',
age:50
})
user.save(function(err){
if(err){
console.log(err)
}
const car1 = new Car({
make:'Toyota',
model:'568',
owner:user._id
})
car1.save(function(err){
if(err){
console.log(err)
}
})
user.cars.push(car1)
user.save()
})
This works but if I need to perform an operation on one Car model,then it obviously wont reflect on the user car array and I have to do it separately i.e the models are not 'actually' linked. How can I make it so that performing an operation like delete on the Car model will automatically delete it from my user car array. Any help will be appreciated thanks.
There is no automatic way to delete cars from user when a car is removed.
So you need to make operation on both the documents.
But there is a simpler way with only parent referencing. Don't keep car references in the user model and use virtual populate to populate cars from user.
Here are the steps:
1-) Change your user schema to setup virtual populate:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
let UserSchema = new Schema(
{
name: String,
age: Number,
},
{
toJSON: { virtuals: true },
}
);
UserSchema.virtual("cars", {
ref: "Car",
localField: "_id",
foreignField: "owner",
});
const User = mongoose.model("User", UserSchema);
Note that I removed the cars field, added toJSON: { virtuals: true } option in the schema, set up virtual. (also modified age type as Number).
2-) Now we can create a user and car like this:
router.post("/users", async (req, res) => {
const user = new User({ name: "Raj", age: 50 });
try {
await user.save();
const car1 = new Car({
make: "Toyota",
model: "568",
owner: user._id,
});
await car1.save();
res.send("User and car saved");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
As you see we needed 2 db operation instead of 3 since we don't need to push the car to the user's cars and save.
3-) Now we can populate the cars from user using populate:
router.get("/users/:id", async (req, res) => {
try {
const user = await User.findById(req.params.id).populate("cars");
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
This will give output:
{
"_id": "5ea685a3f1a0b02db8aaffe2",
"name": "Raj",
"age": 50,
"__v": 0,
"cars": [
{
"_id": "5ea685a5f1a0b02db8aaffe3",
"make": "Toyota",
"model": "568",
"owner": "5ea685a3f1a0b02db8aaffe2",
"__v": 0
}
],
"id": "5ea685a3f1a0b02db8aaffe2"
}
Related
I'm trying to push data to a nested array in mongodb. I'm using mongoose as well.
This is just mock code to see if i can get it working:
User model:
import mongoose from "mongoose";
const CoinSchema = new mongoose.Schema({
coinID: { type: String },
});
const CoinsSchema = new mongoose.Schema({
coin: [CoinSchema],
});
const WatchlistSchema = new mongoose.Schema({
watchlistName: { type: String },
coins: [CoinsSchema],
});
const NameSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
username: { type: String },
});
const UserSchema = new mongoose.Schema({
name: [NameSchema],
watchlists: [WatchlistSchema],
test: String,
});
const User = mongoose.model("User", UserSchema);
export default User;
route:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
const updatedUser = await User.findByIdAndUpdate(id, {
$push: { "watchlists[0].coins[0].coin": newCoin },
});
await updatedUser.save();
// console.dir(updatedUser, { depth: null });
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
request.body // "coinID": "test"
I've tried a lot of different ways to push this data but still no luck. I still get 201 status codes in my terminal which indicates something has been pushed to the DB, but when I check nothing new is there.
Whats the correct way to target nested arrays and push data to them?
It's not perfect but you could get the user document, update the user's watchlist, and then save the updated watchlist like so:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
// get the user
let user = await User.findById(id);
// push the new coin to the User's watchlist
user.watchlists[0].coins[0].coin.push(newCoin);
//update the user document
const updatedUser = await User.findOneAndUpdate({ _id: id },
{
watchlists: user.watchlists,
},
{
new: true,
useFindAndModify: false
}
);
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
I am trying to insert data into MongoDB database but I get this error Cannot read property 'push' of undefined.
I can't understand what is the issue is here in my code. please help me with the solution. I am a Student and learning it.
here I am trying to push service into the category Model. for that, I have created a one to many relations between service and category. but I can't push the services into the category.
Schema design for category & Service =======
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const CategorySchema = new Schema({
name:{
type:String,
required:true
},
services:[
{
type:Schema.Types.ObjectId,
ref:'Service'
}
]
},{ timestamps:true })
const Category = mongoose.model("Cat", CategorySchema);
module.exports = Category;
service======
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const serviceSchema = new Schema({
title:{
type: 'String',
required: true
},
description:{
type: 'String',
required: true
},
image: {
type: 'String',
required: true
},
price: {
type: 'Number',
required: true
},
category: {
type:Schema.Types.ObjectId,
ref:'Cat'
}
})
const Service = mongoose.model("Service", serviceSchema);
module.exports = Service;
here is my service controller
postService:(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
service.save()
.then((service)=>{
const category = Category.findOneAndUpdate({_id: service.category})
category.services.push(service)
category.save()
console.log(category)
return res.redirect("/admin/services");
})
.catch((err) => {
console.log(err);
return res.redirect("/admin/services/create");
});
},
do like this:
postService: async(req, res)=>{
const { title, price, description,category} = req.body;
const image = req.file.filename;
const service = new Service({
title,
price,
category,
description,
image,
});
try {
await service.save()
let categoryModel = await Category.findById(category);//category should be an ObjectId
categoryModel.services.push(service)
await categoryModel.save()
return res.redirect("/admin/services");
} catch (err) {
console.log(err);
return res.redirect("/admin/services/create");
}
},
I do not understand what the problem is.
And why each element from the 'tasks' array is null.
Schema = mongoose.Schema;
const userSchema = new Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
tasks: [{type: Schema.Types.ObjectId, ref: 'Task'}]
}
);
const taskSchema = new Schema({
title: String
});
const User = mongoose.model('User', userSchema);
const Task = mongoose.model('Task', taskSchema);
// Add some default to DB
const task1 = new Task({
title: "Welcome! Here You Can:"
});
const task2 = new Task({
title: "ADD EDIT DELETE SHARE your TASKS "
});
const defaultTasks = [task1, task2];
When create new User I Add defaultTasks
const newUser = {
email: req.body.email,
password: req.body.password,
tasks: defaultTasks
};
Get Users Tasks
app.get('/tasks/', function(req, res){
const email = req.query.user;
User
.findOne({email: email})
.populate('tasks')
.exec()
.then(foundUser => {
console.log(foundUser);
const data = [];
Object.keys(foundUser.tasks).forEach(function(key) {
const val = foundUser.tasks[key];
data.push([val.title, val._id]);
});
res.send(data);
console.log('Data to send ' + data);
});
});
Before .Populate() console.log {
{ tasks: [ 5cf78ac1d08ee617fc89f7ed, 5cf78ac1d08ee617fc89f7ee ]
After { { tasks: [],
Please Help! All that I found did not solve my problem.
Maybe problem in defaultTasks. But i dont see it.
Your code doesn't save your task to DB, it just creates an object. So later when you populate User there are no tasks in DB to be found.
const task1 = await new Task({
title: "Welcome! Here You Can:"
}).save();
// or
const task1 = await Task.create({
title: "Welcome! Here You Can:"
});
P.s. of course you can deal with asynchronous calls the way you want.
I'm trying to use the model.create() shorthand to create a new Company with an existing User ObjectId.
const userSchema = new mongoose.Schema({
firstName: String,
lastName: String
});
const companySchema = new mongoose.Schema({
companyName: String,
users: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}]
});
const User = mongoose.model('user2', userSchema);
const Company = mongoose.model('company2', userSchema);
The following user already exists in the users collection
{"_id":"5a9633031fe445041c07afd3","firstName":"John","lastName":"Doe","__v":0}
Now I want to create a new company with this existing user:
Company.create({
companyName: 'Foo, Inc.',
users: {5a9633031fe445041c07afd3}
}).then(function(err, company) {
console.log(err, company);
});
I've tried variations of the user as:
users: '5a9633031fe445041c07afd3'
users: [5a9633031fe445041c07afd3]
users: [{5a9633031fe445041c07afd3}]
How can I save this document?
try this
let model = new Company();
const body = {
companyName: 'Foo, Inc.',
users: "5a9633031fe445041c07afd3"
};
model = Object.assign(model, body);
model.then((company) => {
console.log(company);
}).catch((err) => {
console.log(err);
})
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I have a Person model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PersonSchema = new Schema({
name: String,
cars: [{
type: Schema.types.ObjectId,
ref: 'Cars'
}]
});
const Person = module.exports = mongoose.model('Person', PersonSchema);
and I have a Cars model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CarsSchema = new Schema({
color: String,
owner: {
type: Schema.Types.ObjectId,
ref: 'Person'
},
});
const Cars = module.exports = mongoose.model('Cars', CarsSchema);
How do I make sure that every time a car is added, it get listed in a particular person's car array?
Right now, I've done something like this:
const newPerson = new Person({
name: 'jared'
});
newPerson.save()
.then(person => {
console.log(person);
});
const newCar = new Car({
color: 'red'
});
newCar.save(function(err, car) {
if (err) {
console.log(err)
} else {
car.populate(
car, {
path: "owner"
},
function(err, car) {
if (err) {
console.log(err);
} else {
console.log(car);
}
});
}
});
the code works without errors, and the car gets properly printed to the terminal with the "jared" person document seen occupying the owner field, but the result isn't saved to MongoDB. Instead, when I check MongoDB, I just see the car with only the "jared" document _id occupying the owner field. Can anyone please tell me why that is?
You have to assign _id from the person to car owner.
let newPerson = new Person({
name: 'jared'
});
newPerson.save()
.then(person => {
console.log(person);
let newCar = new Car({
color: 'red',
owner: person._id
});
newCar.save(function(err, car) {
if (err) {
console.log(err)
} else {
car.populate(
car, {
path: "owner"
},
function(err, car) {
if (err) {
console.log(err);
} else {
console.log(car);
}
});
}
})
});