What data structure should i use in mongoDB - node.js

I am making a small project in MEAN stack but I can not figure out what data structure to use.
So, in this case, I don't have any reference in the store I just fetch store when a person asks for his or her stores.
var personSchema = Schema({
_id : Number,
name : String,
stores: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
});
var storeSchema = Schema({
_id : Number,
title : String
});
AND:
In this case, I give the store a reference of the person so when a person asks for his or her stores I fetch all the store which has a reference to the person.
var personSchema = Schema({
_id : Number,
name : String
});
var storeSchema = Schema({
_id : Number,
owner : { type: Schema.Types.ObjectId, ref: 'Person' },
title : String
});
Which one is better approach?

First one is better to use as it helps in clean code and queries.

Related

Nesting and querying documents with MongoDB

I have a data structure that looks more or less like this:
var city = {
name: String,
mayor: Person,
citizens: [Person]
};
I think my use case is pretty good for using MongoDB, but I have a few questions. The above model has been implemented with mongoose, and I use sub documents to nest Persons inside City.Obviously the citizens array could get quite long, and that's why MongoDB seems like a good choice.
Is this an efficient way to structure my data? I'm wondering if Mongo will have to do some sort join each time I want to select a city, with all of it's citizens (or a large part of them). That would obviously defeat the purpose of using a document database.
Also, when in the mongo terminal i try something like db.cities.find({name:'Berlin'}).mayor I don't get any results. When I try db.cities.find({name:'Berlin'}) it shows the city, and it also shows an object id for the mayor but not all the properties of the mayer/Person.
So how do I query with sub documents and is this a good way of working?
I would recommend your schema as following with Populate. There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.
var personSchema = Schema({
_id : Number,
name : String,
});
var Person = mongoose.model('Person', personSchema);
var citySchema = Schema{
name: String,
mayor: { type: Schema.Types.ObjectId, ref: 'Person' },
citizens: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
};
var City = mongoose.model('City', citySchema);
To query the city like Berlin through
City.find({name: 'Berlin'})
.populate('mayor')
.populate('citizens')
.exec(...)
The mayor and citizens related document will be retrieved from DB.
If you concern there are too many citizens in the city to make the city too large with populate the person in the city, another option is
var personSchema = Schema({
_id : Number,
name : String,
cityId : { type: Schema.Types.ObjectId, ref: 'City' }
});
var Person = mongoose.model('Person', personSchema);
var citySchema = Schema{
name: String,
mayor: { type: Schema.Types.ObjectId, ref: 'Person' }
};
var City = mongoose.model('City', citySchema);
To query the city Berlin with aggregation, here are the sample codes.
City.find({name: 'Berlin'})
.populate('mayor')
.exec(function(err, city) {
Person.aggregate([
{$group: {cityId: city._id, citizens: {$push: '$name'}}}
// ...
], function(err, result) {
//...
});

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!

TTL expiration of Mongoose referenced document

I have a requirement for setting a TTL on a collection of Docs in my app but also need those docs to be referenced by another collection and am unsure how this would work?
Does setting a TTL on a document remove that document from all other reference docs when it is expired or would I have to write a backend process myself and not use mongoDb's TTL indexes?
An example schema of the functionality I would want :
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
createdAt: { type: Date, expires: 60*60*24 },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
So after a Day the Story doc would expire and i would need the ref to that story to expire from the person
You cannot handle this with TTL indexes.
You could use a cron job/scheduled task to remove old documents.
I'd suggest you read this, a nice lightweight way of implementing background processes on MongoDb.
The built-in TTL doc expiration has no support for removing references to expired docs.
You'll need to provide that functionality in your own code if you need it.

Mongo: query on subdocs

Hello I have this problem when checking if a subdocument exist before pushing a new subdocument.
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String,
tasks : [{type: Schema.ObjectId, ref: 'Task'}] // assuming you name your model Task
});
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {type: Schema.ObjectId, ref: 'User'} // assuming you name your model User
});
With this, your query for all users, including arrays of their tasks might be:
User.findOne({...}).populate('tasks').run(function(err, user) {
var subdoc = user.tasks.id(mytask.id);
if(subdoc){
//not exist
//push
}
});
This is the error:
TypeError: Object has no method 'id'
You are getting that error because there is no 'id' field defined for the 'tasks' subdocument. You might have meant 'user.tasks._id', which will return the ObjectId that MongoDB adds to its documents by default.

Why do they use an ObjectId and a Number in the Mongoose Population example?

In this example, they create personSchema using ObjectId to reference the Story and this I understand. But then in storySchema why don't they do the same to reference the person?
Or the inverse: why using ObjectId instead of Number in Person?
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Type of reference has to be the same as the referenced schema's _id property.
In case of personSchema it's a Number.
storySchema on the other hand, has the _id field assigned automatically by mongoose - it's not specified in parameters for the schema constructor.
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior

Resources