I'm not sure the best way to set this up in MongoDB.
I have two collections User and Skill. The collection for Skill has a list of skills that every user should have.
var SkillSchema = new Schema({
name: { type: String, required: true, trim: true },
category: { type: String, required: true, trim: true }
});
mongoose.model('Skill', SkillSchema);
var UserSchema = new Schema({
_id: { type: String, required: true, trim: true },
first_name: { type: String, required: true, trim: true },
last_name: { type: String, required: true, trim: true },
email_address: { type: String, required: true, trim: true },
skills: [{
skill: { type: ObjectId, ref: 'Skill' },
count: { type: Number, default: 0 },
last_performed: { type: Date }
}]
});
mongoose.model('User', UserSchema);
What I am trying to do is have a list of skills, and each user has a count property that shows how many times they have performed the skill, and a last_performed property that has the date they last performed it.
My problem is, I want the list of skills to be same for each user, but I can update their count and last_performed properties uniquely for each user.
The way I have got it currently is referencing the skill id, and then having the count/date in the user schema. The problem with this, is if I add another skill to the Skills schema, the user's skills array won't be updated with the new skill. I figured updating every user every time I add/remove a skill, to reflect the new skills list, wouldn't be the optimal way to do this.
Can you sync the user's skills array to match the Skills schema?
Would it be better to just add each user's count/date to the skill schema directly? The only problem with this is if there are thousands of users, would this have any performance problems, and would it be easy enough to sort the skills by count/date for each user, and query the user's skills individually without returning the counts for every user?
Cheers,
Ben
skills : [{ type: ObjectId, ref: 'Skill' }]. Just push the Ids to the array if you want to add skills when you do a save or an update.
you can populate the array of skills and you can count the skills array. That will give you the count.
If you have last_performed in the Skill model. then you will get access to it after you populate
Related
I have a Mongo DB (latest version) that I am accessing with Mongoose (v6.5.4)
The project is using a discriminator pattern to keep all documents in the same collection.
There are many instances where i need to join documents.
Set up:
// Models:
const UserSchema = new Schema<IUser>(
{
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
});
// There are other similar models to <Team>
const TeamSchema = new Schema<ITeam>(
{
name: {
type: String,
required: true,
},
userIds: {
type: [Schema.Types.ObjectId],
required: true,
ref: "User",
default: [],
},
});
Problem:
I can use populate to return collections of Teams and the userIds be an array of user objects.
Where I am stuck is querying getting an array of users with an added field of teams[].
I've been trying aggregate to no success, I can loop over the users collection and return a list of Teams but this feels wrong and expensive in terms of read units (production data base is on a pay as you go service)
As data models go there is not much going for it - but it is an existing solution
Can anyone advise?
I was being stupid. The from field in my look up was wrong.
Should have been 'teams' not 'Team' which is the model name.
I have a schema "Questions" it has like a dozen of questions in it, I can add and delete those questions, I need this collection reflected in a field of other collection - "User" with one additional field (nested in options).
Question Schema:
var QuestionScema = new mongoose.Schema({
key: { type: String, required: true },
label: { type: String, required: true },
name: { type: String, required: true },
page: { type: String, required: true },
type: { type: String, required: true },
options: [{
key: {type: String, required: true},
value: {type: String, required: true}
}],
});
User Schema:
var UserSchema = new mongoose.Schema({
Name: { type: String, required: true },
Email: { type: String, required: true, unique: true },
Password: { type: String, required: true },
//this is where I need to reflect a Questions collection on each user,
//so that it will look something like this//
Questions: [{
key: {type: String, required: true},
//here can be all other fields from Questions collection, that is not a problem
options: [{
key: {type: String, reuired: true},
value: {type: String, reuired: true},
counter: {type: Number, default: 0} //this is the additional field
}]
}],
//
Notifications: [{
Title: { type: String },
Data: { type: String },
Created: { type: Date, default: Date.now }
}]
});
I can't figure out how to do that.
I have another collection of users, say User2 that will answer those questions from Questions collections and I need to keep track on Users schema (not User2, there I just save questions and answers) of how many times an option for that question is chosen.
A Questiuons entry can look like this:
{
key: Haveyouseenthismovie,
label: Have you seen this movie?,
name: Have you seen this movie?,
page: 1,
type: dropdown,
options: [{
key: yes,
value: yes
}, {
key: no,
value: no
}]
}
I want it to work like that (reflect a collection in field of each User) so I don't have to check if that question is in User collection if not add and if it is, is there an option that I need if it is than increment, if not than add that option (that user selected from options in that question in Questions schema) and increment. That looks like a bummer. So I figured that it will be better if that field will reflect a collection and I will just increment the option that I need on a question that I need.
Please help me figure that out, I don't have enough practise in mongo so I struggle with it sometimes :)
I don't think there is a way to reflect a collection in another document as the way you seem to wish it.
As I understand, the following options are available for you:
Embed the entire question document inside the User documents in User Collection.
Just maintain the '_id' of the question document in the User document in User Collection.
Please read on Data Modelling concepts & maintaining relationship between documents from Mongo DB Page https://docs.mongodb.com/manual/applications/data-models-relationships/
I am developing an app like Tinder to experiment with MongoDB.
I am wondering about the database schema.
The main idea is that a user can "like" many users but no matter how much the number of "liked" profiles grows, it is very unlikely to hit the 16MB document size ceiling, so in my design, "liked" profiles are embedded inside one's profile.
below is a sample of my users schema using mongoose
var UserSchema = mongoose.Schema({
fullName: {
type: String,
trim: true
},
phone: {
type: String,
trim: true,
required: true,
},
gender: {
type: String,
enum: ['male', 'female'],
},
age: {
type: Number,
required: true
},
favorites: []
});
On the other hand, a user might be "disliked" by my many users.
So a user should not see on his next profile search the profiles of users who "disliked" him, so in my design I created a collection that holds the ID of the user who "disliked" and the ID of the user being "disliked".
below is a sample of my blocked schema using mongoose
var BlockedSchema = mongoose.Schema({
BlockerUserId: {
type: String,
required: true
},
BlockedUserId: {
type: String,
required: true
}
});
Do you think this is a good approach? and which indexes needs to be created?
Best,
You can manage dislike in the user collection only, you don't need a new collection.
var UserSchema = mongoose.Schema({
fullName: {
type: String,
trim: true
},
phone: {
type: String,
trim: true,
required: true,
},
gender: {
type: String,
enum: ['male', 'female'],
},
age: {
type: Number,
required: true
},
favorites: [],
dislike[]
});
and search like
var current_user_id = userdata._id;
db.users.find({dislike:{$ne:current_user_id}})
The above code is not syntactically correct but it will give you an idea.
I have a schema like this in MongoDB:
var Customers = new Schema({
name: { type: String, trim: true, index: true, default: null, sparse: true },
facebookId: { type: String, default: null, trim: true, index: true },
friends: [friends]
});
var friends = new Schema({
customer: { type: Schema.ObjectId, ref: 'Customers', required: true },
lastGame: { type: Schema.ObjectId, ref: 'games', required: true, default: null },
lastGameTime: { type: Date, default: null }
});
Now in friends array I have reference of all the customer who are Facebook friend of the particular customer.
Now what I want to do is I have a screen where I want to show all the customers but there I don't want to those customers who are already my Facebook friends i.e for an example lets suppose I have 10 customer in total from 1 to 10, I am customer no 4 who have customer 1,3,5,6 in friends array so my result on the screen should be of user 2,7,8,9,10
I will really be thankful if someone can tell me the way to this stuff by using Query of MongoDb. I have searched and found $nin usage but that works in simple array. I don't get how I can implement this query on an embedded document as in the case of mine.
Look into $elemMatch. This will allow you to identify a specific document in an embedded document array
ElemMatch MongoDB documentation
You can also use $elemMatch in combination with $nin
I solved this issue by using $nin with a simple approach first of all I select all the friends of a particular customer in an array then by using $nin I filtered all the friends from the query and got my result.
I recently started a project using mongodb and nodejs to build a restful web service. Unfortunately mongodb is very new to me, and coming from the relational databases world I'm asking my self a lot of questions.
Let me explain you my problem :
The goal is to build a sort of content management system with social features like a user can post topics that can be shared and commented.
I have 2 possibilities to do this the one using a reference to get topics posted by a user, the second using topics as embedded document of user instead of reference.
So basically I can have these 2 schemas :
var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String
},
first_name: String,
phone: String,
topics: [Topic.schema]
});
var TopicSchema = new Schema({
_creator: {
type: String,
ref: 'User'
},
description: String,
comments: [Comments.schema],
shared_with: [{
type: Schema.ObjectId,
ref: 'User'
}] //[{ type: String, ref: 'User'}]
});
var CommentSchema = new Schema({
_creator: {
type: String,
require: true
},
text: {
type: String,
required: true
},
});
and
var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String
},
first_name: String,
phone: String,
topics: [{ type: Schema.ObjectId, ref: 'Topics'}]
});
var TopicSchema = new Schema({
_creator: {
type: String,
ref: 'User'
},
description: String,
comments: [Comments.schema],
shared_with: [{
type: Schema.ObjectId,
ref: 'User'
}] //[{ type: String, ref: 'User'}]
});
var CommentSchema = new Schema({
_creator: {
type: String,
require: true
},
text: {
type: String,
required: true
},
});
So the first schema uses 1 collection of user document and the second use 1 collection for the user and 1 collection for the topics, this implies to make for example, 2 finds queries to retrieve a user and it's topics but it is also easyer to query directly the topics.
Here is the request I use to retrieve a specific topic with some user info with the first schema :
User.aggregate([
{$match: {
"topics._id":{$in:[mongoose.Types.ObjectId('56158c314861d2e60d000003')]}
}},
{ $unwind:"$topics" },
{$match: {
"topics._id":{$in:[mongoose.Types.ObjectId('56158c314861d2e60d000003')]}
}},
{ $group: {
_id: {
_id:"$_id",
name:"$name",
first_name:"$first_name"
},
topics:{ "$push": "$topics"}
}}
]);
So the question is, what do youh think ? Which is the good schema in your opinion ?
Thanks in advance.
Better solution: using a reference to get topics posted by a user
For this database use, one typically needs to consider the MMAPV1 document size limit (16MB). Putting user, topic, and comments in one document allows the document to grow without bound. If each topic is a page of text (1K), then each user could have about 16,000 topics before the limit is reached. That seems huge, but what happens if you decide to put images, videos, sounds in the topic as the product matures? Converting from an embedded to a normalized schema later would be a lot more work than a simple design choice today.
Similarly, if the comments could grow to cause a topic to exceed the 16MB limit, they should be in a separate collection. Unlikely? Probably. But if you are writing something that will become, say, the Huffington Post - check out comments on their popular articles.
Here is mongo's advice on data model design