Error while defining mongoose schemas - node.js

I am new to mongo and mongoose. I am trying to create 3 collections Users, Articles and Comments. I want the users documents should contain articles that users have saved. The articles object should have users and comments as embedded objects and comments should have embedded user objects.
I want this to be done using the ids of the individual objects so that I can reduce the loading time, but could not find a suitable way to do so using mongoose. Please suggest how should I proceed with the Schema implementation.
var UserSchema = new mongoose.Schema({
name: String,
email: String,
profilePicture: String,
password: String,
readingList: [articleSchema]
});
var commentsSchema = new mongoose.Schema({
content: String,
votes:{
up:[UserSchema],
down:[UserSchema]
},
comments:[commentsSchema],
timestamp:Date.now
});
var articleSchema = new mongoose.Schema({
title: String,
content: String,
image: String,
votes:{
up: [UserSchema],
down: [UserSchema]
},
comments:[commentsSchema],
timestamp: Date.now
});

What you have is failing because articleSchema isn't defined when you're using it in the UserSchema. Unfortunately, you can reverse the order of defining the schema because they're dependent on each other.
I haven't actually tried this, but based on some quick googling there is a way to create the Schema first and then add the properties.
var UserSchema = new mongoose.Schema();
var CommentsSchema = new mongoose.Schema();
var ArticleSchema = new mongoose.Schema();
UserSchema.add({
name: String,
email: String,
profilePicture: String,
password: String,
readingList: [ArticleSchema]
});
CommentsSchema.add({
content: String,
votes:{
up:[UserSchema],
down:[UserSchema]
},
comments:[CommentsSchema],
timestamp:Date.now
});
ArticleSchema.add({
title: String,
content: String,
image: String,
votes:{
up: [UserSchema],
down: [UserSchema]
},
comments:[CommentsSchema],
timestamp: Date.now
});

Related

How to define an object in NodeJS schema?

I currently have a schema like this:
const postSchema = mongoose.Schema({
title: String,
message: String,
name: String,
creator: String,
tags: [String],
selectedFile: String,
likes: { type: [String], default: [] },
createdAt: {
type: Date,
default: new Date(),
},
})
One of the problem that I anticipate is that as the number of users grow, searching the likes array will become inefficient. Is there a way to store the likes array instead as an Object (key would be userId and value could be true) so that finding someone in the Object would become more efficient.
I am also open to hearing any other ideas that you might have.
Thanks!
I want to suggest populate() for this. From that, you can manage a large no. of user information without a problem. You can create a new schema as likes and add the id of the likes document as an id with the populate. Check the below example.
const likeSchema = mongoose.Schema({
type: [String],
default: [] },
});
const Like = mongoose.model("Like", likeSchema);
Then create the postschema like below.
const postSchema = mongoose.Schema({
title: String,
message: String,
name: String,
creator: String,
tags: [String],
selectedFile: String,
likes: {
type: mongoose.Schema.Types.String,
ref: 'Like',
},
createdAt: {
type: Date,
default: new Date(),
},
})
const Post = mongoose.model("Post", postSchema);
You can easily get all the data inside a likes document by populating when running a query like below.
const posts = await Post.findById({creator_id}).populate("likes");
//Below code will print the data of the first element of the type array of relevant likes document.
console.log(posts.likes.type[0]);
Check the populate and population sections of the mongoose documentation to learn more.

How do I set up schema for a song with multiple artist?

I am creating an application to display new music. On the landing page there will be a section that displays the most recently uploaded music. When a user clicks on the song, it will take them to a show template which will display Artist name, title, video, description and artist(s) social medias.
I also want a section that displays all artist included in that song. When a user clicks an artist name it will render a page with all songs that artist has. So I am having an issue creating a schema since one song can have multiple artist.
My old schema was designed to take input from a form and displayed it without any relationships to the artist.
With my new schemas I am trying to create relationships between the artist(s) and song.
Old Schema
const mongoose = require("mongoose");
artistSchema = new mongoose.Schema({
name: String,
title: String,
image: String,
content: String,
description: String,
category: String,
soundcloud: String,
scName: String,
instagram: String,
igName: String,
twitter: String,
twName: String
});
module.exports = mongoose.model("Artist", artistSchema);
New Schemas
const mongoose = require("mongoose");
artistSchema = new mongoose.Schema({
name: String,
social: schema.ObjectId,
music: schema.ObjectId
});
module.exports = mongoose.model("Artist", artistSchema);
const mongoose = require("mongoose");
socialSchema = new mongoose.Schema({
soundcloud: String,
scName: String,
instagram: String,
igName: String,
twitter: String,
twName: String
});
module.exports = mongoose.model("Social", socialSchema);
const mongoose = require("mongoose");
musicSchema = new mongoose.Schema({
title: String,
image: String,
content: String,
description: String,
category: String
});
module.exports = mongoose.model("Music", musicSchema);
After looking around for a while I found some documentation related to what I am trying to do. https://gist.github.com/fwielstra/1025038
So my question is if my schema is set up properly and if I will run into any problems if I continue following the Github documentation.
look into, one to many relationship. one song relates to many artists.
const mongoose = require("mongoose");
musicSchema = new mongoose.Schema({
title: String,
image: String,
content: String,
description: String,
category: String,
artists: [
{
type: Schema.Types.ObjectId,
ref: "Users"
}
]
});
module.exports = mongoose.model("Music", musicSchema);
voters: [
{
type: Schema.Types.ObjectId,
ref: "someModel[artists model]"
}
]

Schema and subdocs in mongoose.js

Learning how to use mongoose, and am trying to design reliably-variable schemas. The app would post to different services (e.g. Twitter, Tumblr) and store them in one collection ("Posts"). There would be some commonalities (e.g. when it was published, or a short summary) but other fields (like post contents, a blog posts's accompanying scripts) would vary.
What's a good way to approach this? Is there a good way to bind together different collections to avoid this in the first place? References/subschemas? Use Schema.Types.Mixed, and reinforce consistency by extending the default methods with safety checks?
// Example pseudo-functioning schemas
const tweetSchema = new mongoose.Schema({
tweetUrl: {type: string, trim: true}
length: Number
});
const blogSchema = new mongoose.Schema({
title: String,
edits: [Date],
slug: { type: String, trim: true},
body: String
});
const postSchema = new mongoose.Schema({
published: Date,
summary: String,
type: String,
contents: blogSchema || tweetSchema
});
Maybe the discriminators could be better option for your case.
Discriminators are a schema inheritance mechanism. They enable you to have multiple models with overlapping schemas on top of the same underlying MongoDB collection.
Sample codes as below
var options = {discriminatorKey: 'contents'};
const postSchema = new mongoose.Schema({
published: Date,
summary: String,
type: String,
}, options);
var Post = mongoose.model('Post', postSchema);
const tweetSchema = new mongoose.Schema({
tweetUrl: {type: string, trim: true}
length: Number
}, options);
var Tweet = Post.discriminator('Tweet', tweetSchema);
const blogSchema = new mongoose.Schema({
title: String,
edits: [Date],
slug: { type: String, trim: true},
body: String
}, options);
var Blog = Post.discriminator('Blog', blogSchema );

Complex sort with Mongoose

I'm new in Mongoose and I want to create a 'complex' sorting. So I have the following schemas:
var UserSchema = new Schema({
firstName: String,
lastName: String,
...
skills : [{ type: Schema.Types.ObjectId, ref: 'Skill' }]
});
var ProjectSchema = new Schema({
name: String,
description: String,
...
skills : [{ type: Schema.Types.ObjectId, ref: 'Skill' }]
});
var SkillSchema = new Schema({
name: String
});
So given those schemas what I need is to sort by the matching percentage between the user skills and the project skills, so basically I want to show first the projects that are more related to the user. Is that possible by using just mongoose? If so I guess I will need to create a sorting function that I can pass to the query or something.
Thank you!

ReferenceError: <model> is not defined

I have several schemas defined. Here's one that works fine:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NewsSchema = new Schema({
name: String,
route: String,
remoteURL: String,
articles: [{title: String, link: String, Image: String, contentSnippet: String}],
retrieved: Date,
dormant: { type: Boolean, default: false}
});
module.exports = mongoose.model('News', NewsSchema);
Here's a second one that's nearly identical:
var mongoose = require('mongoose'),
Schema = mongoose.Schema
// NewsSchema = new Schema({ name: String });
var ArticlesSchema = new Schema({
title: String,
link: String,
pubDate: Date,
image: String,
contentSnippet: String,
sourceName: String
// sourceId: [ {type: Schema.Types.ObjectId, ref: NewsSchema}]
});
module.exports = mongoose.model('Articles', ArticlesSchema);
I've loaded both of the modules at the top of my program, along with a bunch of other stuff like this:
players = require('./app/models/players'),
articles = require('./app/models/articles'),
If I create an instance of the first one with something like:
var player = new Players();
But if I try to create an instance of the second one with:
var item = new Articles();
I receive the error in the subject. In tracing the code I can see that the modules are in scope, so I don't believe it's something stupid like redefining a variable or something like that.
Any ideas?
There is a missing quote mark, so
Instead of
sourceId: [ {type: Schema.Types.ObjectId, ref: NewsSchema}]
use
sourceId: [ {type: Schema.Types.ObjectId, ref: 'NewsSchema'}]
would solve your problem.

Resources