Does Mongoose only support embedded documents in arrays? - mongodb

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!

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.

Best practices with connecting data from 2 models

I've got two models: Note and Profile. Note contains foreign key of connected profile as you can see below.
Note: {
profile_id: String,
date: String,
content: String,
}
Profile: {
id: String,
name: String,
profilePicture: String
}
I want to get all notes and also name and profile picture of note.
In this situation should I:
get all notes and all profiles and then join them locally in for loop,
get all notes and then in for loop ask DB for name and picture of matching profile,
other option
Which way is recomended?
Take a look at mongoose's Populate. You can declare a Schema property with type: Schema.Types.ObjectId, ref: 'Profile'. When you run a Query you can .populate() this field with the corresponding document.

How can I search on a field and return the object

I made a beer matching dating app for a school assignment. Unfortunately am I having a bit of trouble finding out how to search in my database on a template injected number as object.
I've tried this I read on MongoDB docs
The database looks like this :
beerProfile: Object
↳24589: Object
↳name: "Heineken"
img: "https://untappd.akamaized.net/site/beer_logos/beer94130_52756_sm.jpeg"
description: "Heinken is a beer"
bid:"24589"
So beerProfile is an object and has the object 24589 inside it. Inside the 24589 object are name, imd, description and bid.
I tried to use the find() function. ( the collection is called users )
db.collection('users').find( { [24589]: [{name: [Heineken]}] }, { name: 1, bid: 1 }, done);
And I also tried :
db.collection('users').find( { $text: { $search: 24589 } }, done);
I would like to make it return the object values of the 24589 object. Does anyone how I can achieve this ?
I think your "schema" became unnecessarily complex by using a variable (24589) as a key. You should change it to something like this:
beerProfile: Object
↳beer: Object
↳name: "Heineken"
img: "https://untappd.akamaized.net/site/beer_logos/beer94130_52756_sm.jpeg"
description: "Heinken is a beer"
bid:"24589"
Then you can use a simple find():
db.collection('users').find( { "beer.bid": "24589"})

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

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/

Mongoose Reference for simple code reference values?

I'm designing a MongoDB schema to save a fairly large/nested document. I'm planning on embedding as much as possible into a single document, but wasn't sure what to do with code/lookup values. For example, if we have a code table representing "priority", with the possible values being:
low
medium
high
Is this something I should use a Mongoose reference for, and create a simple document to hold priority, eg something like:
var PrioritySchema = new Schema({
description: String
});
This would then be referenced with something like the following:
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { type: String, ref: 'Priority' }
});
Or is this overkill? The thing I want to avoid is directly storing these "descriptions" in the main/overall model, then having a requirement change sometime in the future. For example, someone decides that instead of "medium", we need to call it "somewhat". In that situation, I assume I'd be stuck doing some sort of data migration?
you can do this :
var PrioritySchema = new Schema({
description: String
});
and this
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { PrioritySchema }
});
But if you want what you described further I would advise you to do this instead :
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { type: Schema.Types.ObjectId, ref: 'Priority' } // see this : Schema.Types.ObjectId != String
});
Let's make it simple if you need those values to be cross-documents you need to use reference. If the values are only existing because of the parent document then you can choose embing.
For more information read this :
http://mongoosejs.com/docs/2.7.x/docs/embedded-documents.html
FYI : I used to struggle a lot with this. If you follow the path of embing all nested sub-document you will face a lot of "What Why I can't do that :'(. At the end I choosed the referencing way I felt more confortable with it. embing != referencing.