How to implement a many-to-many collection in meteor+mongo such that the collection is searchable and/or sortable by all possible fields? - mongodb

I am trying to implement a collection in meteor/mongo which is of following nature:
FIRST_NAME-------LAST_NAME-------------CLASSES----------PROFESSORS
----------A-----------------------B------------------------------a---------------------b
-------------------------------------------------------------------c---------------------d
-------------------------------------------------------------------e---------------------f
-------------------------------------------------------------------g---------------------h
-------------M-------------------------N------------------------c---------------------d
-------------------------------------------------------------------p---------------------q
-------------------------------------------------------------------x---------------------q
-------------------------------------------------------------------m---------------------n
-------------------------------------------------------------------r---------------------d
So as above, a person can take multiple classes and a class can have multiple people. Now, I want to make this collection searchable and sortable by all possible fields. (Also that one professor can teach multiple classes.)
Searching by FIRST_NAME and LAST_NAME is easy in above shown model. But, I should be able to see all student depending on the class I select. I would also want to see list of classes sorted in alphabetical order and also the people enrolled in corresponding classes?
Can you please let me know how to approach this in a meteor/mongo style? I would also be glad if you could lead me to any resources available on this?

You are describing one of the typical data structures which are better suited for a relational database. But don't worry. For reasonably sized data sets it is quite workable in MongoDB too.
When modelling this type of structure in a document database you use embedding, which does lead to data duplication, but this data duplication is typically not a problem.
Pseudo-code for your model:
Collection schoolClass: { // Avoid the reserved word "class"
_id: string,
name: string,
students: [ { _id: string, firstName: string, lastName: string } ],
professor: { _id: string, firstName: string, lastName: string }
}
Collection student: {
_id: string,
firstName: string,
lastName: string,
classes: [ { _id: string, name: string } ]
}
Collection professor: {
_id: string,
firstName: string,
lastName: string,
classes: [ { _id: string, name: string } ]
}
This gives you easily searchable/sortable entry points to all objects. You only follow the "relation" _id to the next collection if you need some special data from an object. All data needed for all documents in the common queries should be present in the Collection the query is run on.
You just need to make sure you update all the relevant collections when an object changes.
A good read is https://docs.mongodb.com/manual/core/data-modeling-introduction/

Related

Whats the difference between having an array of objects and array of ObjectIds on mongoDB?

Suppose I have the following schema:
const personSchema = mongoose.Schema({
firstname: String,
lastname: String,
email: String,
gender: {type: String, enum: ["Male", "Female"]}
dob: Date,
city: String,
interests: [interestsSchema],
// vs this
// interests: [{type: Schema.Types.ObjectId(), ref: 'Interest'}]
});
What are the difference between the two methods here? What are the advantages and disadvantages of one vs the other?
There is obviously no perfect answer to this question, it all depends on the scenario, where and how will you use the data.
ObjectId vs Embedded
I use both embedded documents and lists of ObjectIds. For example, I have two collections, Customers and Contacts. Every Customer can have multiple contacts, and multiple Customers should be able to use the same contact.
We also want to list and manage contacts separately.
We also have an array of addresses, which is unique to each Customer document, we do not need to list or manage them separately or reuse them ever again, so it makes sense to embed them.
Customer
{
businessName: string,
contacts: [ObjectId, ObjectId],
address: {
invoice: [{
street: string
zip: string
city: string
}]
}
}
Contact
{
firstName: string
lastName: string
phoneNumber: string
email: string
}
Array size
This is just a side note, not relevant to the question, just some more information about arrays in MongoDB.
What you are describing here is a so called one-to-many relationship, where one document may have any number of embedded documents.
MongoDB works best with "one-to-few" when using any type of array, they usually recommend you to not have an array containing more than a hundred documents, if there are more, it will start to impact query times in one way or another.
The same goes for the ObjectId array, it should not be more than a hundred in the array.
If you expect the array to increase beyond a hundred, you should use a separate collection with a property like personId where every interest refers to the person. This way, you don't need the array at all in the personSchema.

Postgres graph with TypeORM or something better?

I need store and build fast query for next structure:
class Model {
id: number:
alias: string;
schema: Record<string, any>;
}
where schema it's can be:
{
someField: '$model_alias',
otherField: {
nestedField: '$other_model_alias'
}
}
Example data:
{ id: 1, alias: "model_one", schema: { field1: "test", field2: "demo" } }
{ id: 2, alias: "model_second", schema: { someField: "$model_one", otherField: { nestedField: 5 } }
{ id: 3, alias: "model_third", schema: { field5: "$model_second", field6: "$model_one", field7: "$model_fourth" } }
{ id: 4, alias: "model_fourth", schema: { field8: "$model_second" } }
As you can see, json field schema contains fields which may refer to another models with schemas. Thus, there can be a lot of nesting, and relationships can be many-to-many.
Is it possible to achieve such a structure with Postgres or should some alternative be used? I need possible to easy manage structure and very fast queries (get tree children or get tree parents).
Thanks.
Choosing the right db type is tricky at the best of times. Can you provide more information about what sorts of queries you'd be doing? And how big is your dataset?
If your requirement is to exclusively get the parents and children of a model, a relational db such as postgres would do it. If the relations are many-to-many, you'll have a bridging table (https://dzone.com/articles/how-to-handle-a-many-to-many-relationship-in-datab), and will be able to do efficient queries on that.
If you're doing significant, multi-hop traversals between the relationships, you might indeed want to look at a graph database to avoid expensive joins. Postgres even has a plugin that allows this: https://www.postgresql.org/about/news/announcing-age-a-multi-model-graph-database-extension-for-postgresql-2050/
I wouldn't recommend a document store for data that's heavily relational like this, just because managing relationships between documents has to be handled manually by the user, and that's normally more trouble that it's worth.

Mongoose Schema for User profile, that has one to many properties

I used to use MySQL and now new to Mongodb. In phase of learning, I am trying to create a User Profile like LinkedIn. I am confused to choose the proper way of creating one-to-many relationship in mongodb schemas.
Context: A user can have multiple education qualification and same with experience. Here are two ways, that i tried to create the schema as:
Example 1:
var userSchema = new mongoose.Schema({
name: {
first: String,
middle: String,
last: String,
},
gender: { type: Number, max: 3, min: 0, default: GENDERS.Unspecified },
age: Number,
education: [{type: Schema.Types.ObjectId, ref:'Education'}],
experience: [{type: Schema.Types.ObjectId, ref:'Experience'}],
email: String
});
Example 2:
var userSchema = new mongoose.Schema({
name: {
first: String,
middle: String,
last: String,
},
gender: { type: Number, max: 3, min: 0, default: GENDERS.Unspecified },
age: Number,
education: [{type: String, detail: {
major: String,
degree: String,
grade: String,
startdate: Date,
enddate: Date,
remarks: String
}}],
experience: [{type: String, detail: {
position: String,
company: String,
dateofjoin: String,
dateofretire: String,
location: String,
responsibilities: [{type:String}],
description: String,
}}],
email: String
});
I haven't tested the second option.
Which one is better and easier during writing querying to fetch or add data? Is there a better way to write schema for scenarios like that?
For this particular example I would suggest embedding the documents vs storing as reference, and here is why.
Usually my first step in mongodb schema design is to consider how I will be querying the data?
Will I want to know the educational background of a user, or will I want to know all users who have a particular educational background? Having answers to these types of questions will determine how you want to setup your database.
If you already know your user, having the embedded educational background within that document is quick and easy to access. No separate queries are needed, and the schema still isn't overly complex and difficult to comprehend. This is how I would expect you would want to access the data.
Now, if you want to find all users with a particular educational background, there are obviously large drawbacks to the embedded document schema. In that case you would need to first look at each user, then loop through the education array to see all the various educations.
So the answer will be dependent on the expected queries you will be making to the data, but in this case (unless you are doing reporting on all users) then embedded is probably the way to go.
You may also find this discussion helpful:
MongoDB relationships: embed or reference?

Mongoose product category design?

I would like to create an eCommerce type of database where I have products and categories for the products using Mongodb and Mongoose. I am thinking of having two collections, one for products and one for categories. After digging online, I think the category should be as such:
var categorySchema = {
_id: { type: String },
parent: {
type: String,
ref: 'Category'
},
ancestors: [{
type: String,
ref: 'Category'
}]
};
I would like to be able to find all the products by category. For example "find all phones." However, the categories may be renamed, updated, etc. What is the best way to implement the product collection? In SQL, a product would contain a foreign key to a category.
A code sample of inserting and finding a document would be much appreciated!
Why not keep it simple and do something like the following?
var product_Schema = {
phones:[{
price:Number,
Name:String,
}],
TV:[{
price:Number,
Name:String
}]
};
Then using projections you could easily return the products for a given key. For example:
db.collection.find({},{TV:1,_id:0},function(err,data){
if (!err) {console.log(data)}
})
Of course the correct schema design will be dependent on how you plan on querying/inserting/updating data, but with mongo keeping things simple usually pays off.

Does Mongoose only support embedded documents in arrays?

I have some data in MongoDB that looks like this:
{
name: "Steve",
location: {
city: "Nowhere, IL",
country: "The United States of Awesome"
}
}
I’m using objects to organize common data structures (like locations), which in Mongoose might map nicely to Schemas. Unfortunately, they don't appear to really work in Mongoose.
If I just embed an object, like this:
{
name: String,
location: {
city: String,
country: String
}
}
It appears to work, but exhibits some bizarre behavior that causes problems for me (e.g. instance.location.location returns location, and subobjects inherit methods from the parent schema). I started a thread on the Mongoose list, but it hasn’t seen any action.
If I embed a Schema, like this:
{
name: String,
location: new Schema({
city: String,
country: String
})
}
…my application doesn’t start (Schema isn’t a type supported by Mongoose). Ditto for
{
name: String,
location: Object
}
…which wouldn’t be ideal, anyway.
Am I missing something or do my schemas not jive with Mongoose?
I did something similar:
var Topic = new Schema({
author : ObjectId
, title : String
, body : String
, topics : [Topic]
});
This worked fine in my tests. However, removing the array brakets resulted in an error. Looks like a bug to me.
https://github.com/LearnBoost/mongoose/blob/master/lib/mongoose/schema.js#L185
Dumping types, I only get String, Number, Boolean, DocumentArray, Array, Date, ObjectId, Mixed -- which appears to be on purpose, schema/index.js doesn't look like it dynamically registers new Schemas to the list of types, so I am guessing this isn't a supported use case, yet.
https://github.com/LearnBoost/mongoose/issues/188
"Embedding single docs is out of the question. It's not a good idea (just use regular nested objects)"
Josh
It looks like this was a bug, it’s been fixed in Mongoose 2.0!