Users in my database are declared inside a class as follows:
class User {
constructor() {
this.user = mongoose.model('user', {
email: String,
name: String,
})
}
validPassword(collection, password) {
... ...
}
}
const user = new User();
module.exports = user;
In my PostSchema, I want author to point to the above Schema, but I don't know how to write the part after ref:. I tried User, it gave me an error MongooseError: Schema hasn't been registered for model "User".
var PostSchema = new mongoose.Schema({
title: { type: String, default: "DefaultTitle" },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
})
Could anyone help?
Turn your ref to 'user' with a downcase.
This notation refers to mongodb dbref
The ref is the collection name wich is in your case (according to the schema declaration) "user" in downcase.
This will be your Post declaration :
var PostSchema = new mongoose.Schema({
title: { type: String, default: "DefaultTitle" },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'user' },
})
Related
I am creating personal collection web app in which users can create their own collection including different item such as books, whiskey, poststamps... etc. I created schema for this but now i realised i created only for items not for collections. So i need some help to define my collections schema in which users can create different items and some properties of item should be changeable because of item type.For example, I want to store a book collection. I can select (add to standard set of id+name+tags) additional string field “Author”, additional text field “Synopsis”, addition data field “Publication Year”. Maybe with Whiskey or another collection
Here is my DB structure:
User Schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
import bcrypt from "bcrypt";
const userSchema = new Schema(
{
username: { type: String },
email: { type: String, unique: true},
password: { type: String },
role: { type: String, enum:["user", "admin"], default:"user"},
status: {type: String, default:"active"},
collections: [{ type: Schema.Types.ObjectId, ref: 'Collection' }]
},
{ timestamps: true }
);
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
comments:[{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
text: String,
}],
user: [{ type: Schema.Types.ObjectId, ref: "User" }],
likes:[{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
collectionSchema.index({'$**': 'text'});
export default model("Collection", collectionSchema);
Making an app with a variety of schemas, many having other objects (Schema.Types.ObjectIds) as their properties.
When doing this, I can access the sub-object's property, as long as that sub-object's property is a string. But I'm having issues with it if that sub-object's property is yet another object (and then I need to query properties from that, string or not). For example, the first works fine:
user schema-> friends property of user (which is a list of user objects) -> username property of friend (which is a string)
But this I'm having issues with, I'm getting a string id and not the actual object**:
user schema-> profilePosts property of user (which is a list of profilePost objects) -> author property of profilePost (which is a user object)** -> author username property of profilePost (which is a string)
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {type: String, required: true},
password: {type: String, required: true},
friends: [{type: Schema.Types.ObjectId, ref: "User"}],
profilePosts: [{type: Schema.Types.ObjectId, ref: "ProfilePost"}],
friendRequests: [{type: Schema.Types.ObjectId, ref: "User"}],
})
module.exports = mongoose.model('User', UserSchema);
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ProfilePostSchema = new Schema({
date: {type: Date, required: true},
author: {type: Schema.Types.ObjectId, ref: "User"},
content: {type: String, required: true},
comments: [{type: Schema.Types.ObjectId, ref: "ProfilePostComment"}],
likes: [{type: Schema.Types.ObjectId, ref: "User"}],
hostProfile: {type: Schema.Types.ObjectId, required: true,ref: "User"},
})
module.exports = mongoose.model('ProfilePost', ProfilePostSchema);
exports.user_friends_render = async (req,res) => {
try {
const ViewedProfile = await User.find({}, 'username friends profilePosts friendRequests').populate('friends').populate('profilePosts').populate('friendRequests');
res.status(200).json(ViewedProfile);
} catch(error) {
res.status(200).json({message: error.message});
}
}
objects are string ids instead of objects
Mongoonse populate root object but not implicit deep populate
You can replace string by object as argument at populate method,
for provide full path to populate
const ViewedProfile = await User
.find({}, 'username friends profilePosts friendRequests')
.populate('friends')
.populate({
path: "profilePosts",
populate: [
{
path: "author",
// model: UserModel
},
{
path: "comments",
// model: ProfilePostCommentModel
},
{
path: "likes",
// model: UserModel
},
{
path: "hostProfile",
// model: UserModel
}
]
})
.populate('friendRequests');
You can see fully post at this problem.
Working into NodeJS with Typescript. So the major issue is I am trying to follow the One-To-Many Document structure using Mongoose. But as the question says, I face the issue:
throw new TypeError(`Invalid schema configuration: \`${name}\` is not ` +
TypeError: Invalid schema configuration: `Todo` is not a valid type at path `ref`
Here is the Model Code:
const Schema = mongoose.Schema;
const userSchema = new Schema({
_id: Schema.Types.ObjectId,
firstname: {
type: String
},
lastName: {
type: String,
},
email: {
type: String,
required: "Enter Email ID"
},
password: {
type: String,
required: "Enter Password"
},
todos: [
{
ref: 'Todo',
_id: Schema.Types.ObjectId
}
]
});
const todoSchema = new Schema({
_id: Schema.Types.ObjectId,
title: {
type: String,
required: "Enter a title"
},
createdAt: {
type: Date,
default: Date.now
},
content: {
type: String
}
})
export const Todo = mongoose.model('Todo', todoSchema);
export const User = mongoose.model('User', userSchema);
when you define a reference property in a schema, you just need to define its type and mention it references to which db model
the type should be an objectId
the schema should be something like this
const Schema = mongoose.Schema;
const userSchema = new Schema({
_id: Schema.Types.ObjectId,
firstname: {
type: String
},
lastName: {
type: String,
},
email: {
type: String,
required: "Enter Email ID"
},
password: {
type: String,
required: "Enter Password"
},
todos: [
{
type: Schema.Types.ObjectId, // here is the issue
ref: 'Todo'
}
]
});
hope it helps
This is just a more concise solution to Mohammed's solution.
type is the most important object key while defining your schema and it is missing for your todo field. You need to set type to ObjectId like this
const Schema = mongoose.Schema;
const userSchema = new Schema({
...
todos: [
{
type: Schema.Types.ObjectId,
ref: 'Todo'
}
]
});
I'm trying to embed a model in a mongoose schema. Here's what I have:
const People = {
userId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'User'
},
locationId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'Location'
},
};
const Person = mongoose.model(
'Person',
new mongoose.Schema({
...People,
gender: {
type: String
}
})
);
const shmanian = await new Person({gender: 'other', userId:'someUserId', locationId: 'someLocationId'}).save();
The response I get is {gender: 'other'}
The problem is that people doesn't get populated when I create Person.
You should embed an array of "Person" inside a model "People". For example,
const Schema = require("mongoose").Schema;
const model = require("mongoose").model;
const Person = new Schema({
userId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'User'
},
locationId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'Location'
},
});
const People = new Schema({
person: [Person]
});
module.exports = model("People", People);
Here, everytime you create a new Person, you can add it to the People model which contains an array of Person objects.
Not a mongoose Problem.
People is undefined when you create the Object Person.
Thus it doesn't get populated.
Try switching both assignments.
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));
});