How to access one model Schema in another model mongoose database - node.js

I have two schemas one is user schema in user.js file and other is product schema in product.js file
My user schema in user.js file as follows:
var userSchema = new Schema({
firstname: {
type: String,
required: true
},
lastname: {
type: String,
required: true
},
password: {
type: String,
required: true
},
mobileno: {
type: Number,
unique: true,
required: true
},
facebookid: {
type: String
},
userimage: {
type: String
}
});
and I am overriding automatically generated _id using mongoose-auto-increment module to get automatically incremented userId in user collection.
And my product schema in product.js file as follows:
var productSchema = new Schema({
userId: {
type: String,
required: true
},
productName: {
type: String,
required: true
},
productId: {
type: String,
required: true
},
price: {
type: Number,
unique: true,
required: true
},
prodcutImage: {
type: String
}
});
When user will add new products in collection he will fill all the fields mentioned in product schema. I want to verify that entered userId is exists in user collection or not when new product is added by user in product collection.
I tried to access userSchema.find method in productSchema pre save hook
productSchema.pre('save', function (next) {
userSchema.findOne({'_id': userId}, function(err, user)
{
console.log(user);
});
}
But It returns an error. Can somebody help me in this issue.

You can do like this
app.get('/user/:id', function (req, res, next) {
userSchema.findOne({'_id': userId}, function(err, user)
{
if(user){
next()
}else{
res.json("user id is not valid");
}
});
}, function (req, res, next) {
// code to add your product in product schema
})
more better way is to use Router-level middleware of express

Related

MongoDB relation between two collections by ID with the Express

I am facing a problem while making a relation between two collections (I am using MEAN stack)
I have two collections: Books and Authors
In frontend I want to make a CRUD menu, where I add a new book in the table and then from there i insert a few data about book and then I choose author from the dropdown menu (fetchin data from Authors collection)
So at the end my Book collection needs to have a few data about the book and then inside the object i need an array of data about those author.
Book schema:
const BookSchema = new mongoose.Schema({
owner: { type: String, required: true },
pagesNo: { type: String, required: true },
releaseDate: { type: String, required: true },
country: { type: String, required: true },
authorID: { type: String, required: true }, <-- HERE I NEED DATA ABOUT AUTHOR
});
Author schema:
const AuthorSchema = new mongoose.Schema({
name: { type: String, required: true },
surname: { type: String, required: true },
dateOfBirth: { type: String, required: true },
countryOfBirth: { type: String, required: true },
});
Book route: book.ts
router.get("/", async (req, res) => {
try {
const books= await Book.find();
let Author = await Author.find({
books: { $elemMatch: { _id: books.bookID } },
});
res.status(200).json(books);
} catch (err) {
res.status(404).json({ success: false, msg: "Booknot found" });
}
});
The problem is somewhere inside the find() function.. Is it even a good practice? I want that it can handle a lot of data.
Thanks to everyone!
Greetings.
Your Book schema would be like this:
const MongooseSchema = new mongoose.Schema({
owner: {
type: String,
required: true,
},
pagesNo: {
type: String,
required: true,
},
releaseDate: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
authorId: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
});
And your Author Schema would remain the same (in order to link both schemas).
Your route would be like this (if you want to search all books along with their author names):
router.get('/', async (req, res) => {
try {
const books = await Book.find().populate('authorId');
res.status(200).json(books);
} catch (err) {
res.status(404).json({ success: false, msg: 'Booknot found' });
}
});
And in case you want to search for books with a specific author id then your route would be like this:
router.get('/', async (req, res) => {
try {
const books = await Book.find({ authorId }).populate('authorId');
res.status(200).json(books);
} catch (err) {
res.status(404).json({ success: false, msg: 'Booknot found' });
}
});
AuthorID should be type ObjectId, not string.
To join data from other table, you have to use an aggregate with a lookup.
let author = await Author.aggregate([
{
$lookup:
{
from: "books",
localField: "_id",
foreignField: "authorID",
as: "books"
}
}
]);

children in a mongoose schema wont save incremented numbers but only once

I have a user schema and I am able to increment the number and save to DB, but for children of the schema within an array I am also able to increment the number but it wont save to DB.
const userSchema = new Schema({
inDex: {type: Number, default: 0},
userName: {
type: String,
require: true,
unique: true,
},
email: {
type: String,
lowercase: true,
unique: false,
},
password: { type: String, required: true },
mnemonic: {
type: String,
required: true,
},
profiles: [address: {index: {type: Number, default: 0}]
})
const User = mongoose.model('user', userSchema);
async function processUserInput(req, res) {
User.findById({ _id: userId}).then((doc)=> {
doc.inDex = doc.inDex+1 // Will Increment and Save
doc.profiles[0].address.index =
doc.profiles[0].address.index+1 //Will increment BUT WONT SAVE
doc.save()
}).catch(err => console.log('err', err))
}
router.post('/', async (req, res) => {
await processUserInput(req,res)
res.status(200).json(some json data)
})

Mongoose find documents where field = req.body.user

I have a user schema and a post schema, wherein a user has many posts. I would like to return all posts that the user has on a route called '/post/dashboard'.
Here is my schemas:
let UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
default: null,
},
profile_pic: {
type: String,
default: '/img/profilepic.png',
},
posts: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}
})
let PostSchema = new Schema({
title: {
type: String,
},
description: {
type: String,
}
original_poster: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
tags: {
type: [String]
}
})
So, for example something like:
app.get('/', (req,res) => {
Post.find({ original_poster: req.session.user }).then((posts) =>{
res.send(JSON.stringify(posts));
}) //where req.session.user is an id (the logged in user's object id or _id)
})
Essentially in sql syntax it might be something like:
SELECT * FROM POSTS WHERE ORIGINAL_POSTER = <req.session.user>
What is the proper way to return all posts by the req.session.user?
It seems that original_poster field represent a reference to User's model, If req.session.user is stored as a string you have to cast it to objectID:
const mongoose = require('mongoose');
...
let userId = mongoose.Types.ObjectId(req.session.user);
Post.find({ original_poster: userId }).then((posts) => {
res.send(JSON.stringify(posts));
});

Referencing Object Id not working in Mongoose 4.11.6

I have this problem. Basically, I have 2 schemas - a User schema and a Document schema. The Document schema has an owner which references the _id field of documents in the User collection.
The problem is that I am still able to save documents in the Document collection with owner ids that do not exist in the User collection which should not be so.
Here is my User schema and Document schema respectively
const UserSchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
validate: [{ validator: value => isEmail(value), msg: 'Invalid email.'
}],
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
isAdmin: {
type: Boolean,
default: false,
},
}, {
timestamps: true,
});
const User = mongoose.model('User', UserSchema);
And the Document Schema
const DocumentSchema = new Schema({
title: {
type: String,
required: true,
},
text: {
type: String,
},
access: {
type: String,
enum: ['public', 'private'],
default: 'public',
},
owner: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
}, {
timestamps: true,
});
const Document = mongoose.model('Document', DocumentSchema);
Any help will be appreciated thanks.
For that situation you can add pre save function in your Document schema that will call before save your Document.
const DocumentSchema = new Schema({
// ...
}, {
timestamps: true,
});
DocumentSchema .pre("save",function(next) {
var self = this;
if (self.owner) {
mongoose.models['User'].findOne({_id : self.owner }, function(err, existUser){
if(err){
return next(false, err);
}
if(!existUser)
return next(false, "Invalid user reference");
else
return next(true);
});
} else {
next(false, "Owner is required");
}
});
const Document = mongoose.model('Document', DocumentSchema);

Mongoose preventing saving two documents and sub documents

I'm running into an issue using Mongoose, Express where I want to save a sub document to my user by pushing it into the sub document array, which I can do. However the issues arise when I want to delete a gamesession that is stored in the users "sessions" attribute and also delete the gamesession globally. I think the issue arises because I'm saving two seperate instances of a gamesession. Here is the code for creating a new sub document called "gamesession" and pushing it onto the users "session" attribute
//POST /posts
// Route for creating gamesessions for specific user
router.post("/gamesessions/:uID/", function(req, res, next) {
var gamesession = new GameSession(req.body);
req.user.sessions.push(gamesession);
gamesession.postedBy = req.user._id;
req.user.save(function(err, user) {
if(err) return next(err);
gamesession.save(function(err, gamesession){
if(err) return next(err);
res.json(gamesession);
res.status(201);
});
});
});
Here is my UserSchema
var UserSchema = new Schema({
posts: [PostSchema],
sessions: [GameSessionSchema],
email: {
type: String,
unique: true,
required: true,
trim: true
},
username: {
type: String,
unique: true,
required: true,
trim: true
},
password: {
type: String,
required: true
}
});
And my GameSessionSchema
var GameSessionSchema = new Schema({
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
region: {
type: String,
required: true
},
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
game: {
type: String,
required: true
},
age: String,
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
platform: {
type: [String],
enum: ["Xbox One", "PS4", "PC"],
required: true
}
});
Edit: Adding my delete route to see if that helps
//DELETE /posts/:id/comments/:id
//Delete a specific comment
router.delete("/gamesessions/:uID/sessions/:gID", function(req, res) {
var gamesession = new GameSession(req.body);
gamesession.remove(function(err) {
req.user.save(function(err, user) {
if(err) return next(err);
res.json(user);
});
});
});
Then, when I want to delete a gamesession with a route, it only deletes the instance saved in user.sessions and when I want to query all gamesessions, it's still there, but deleted in my User document. Any ideas? I think it's because I'm saving the document twice, and if so, what's the best way to save it in user.sessions while also being able to delete from user.sessions and querying a global session.
Possibly not saving the removed gamesession from the GameSession document?
router.delete("/gamesessions/:uID/sessions/:gID", function(req, res) {
var gamesession = new GameSession(req.body);
gamesession.remove(function(err) {
req.user.save(function(err, user) {
if(err) return next(err);
gamesession.save(function(err, gamesession){
if(err) return next(err);
res.json({message: 'Updated GameSession Doc'}, gamesession)
})
res.json(user);
});
});
});

Resources