I am using a mongo based DB schema where I have list of ReferenceFields (ObjectIds).
So assume I have two models : User, Group
User Object :
{
"_id" : ObjectId("554ba2897fdd66239457fb33"),
"name" : "something"
}
Group Object :
{
"_id" : ObjectId("453490sdkjskldfjlskdjf"),
"name" : "group_name",
users : [ ObjectId("554ba2897fdd66239457fb33"), ObjectId("554ba28a7fdd66239457fb34") ]
}
ExtJS User Model
Ext.define('Group',{
extend: 'Ext.data.Model',
idProperty : 'id',
fields:[
{name:'group_id', type : 'string', mapping : '_id', persist : false},
{name:'name', type : 'string', mapping : 'name', persist : false}
],
hasMany : { model : 'User', foreignKey:'id' , name : 'users'}
});
The User Model:
Ext.define('User',{
extend: 'Ext.data.Model',
idProperty : 'id',
fields:[
{name:'id', type : 'string', mapping : '_id', persist : false},
{name: 'name', type: 'string'},
]
});
in EXTJS code when I access group.users();
Using the rest method in stores when I add associations to models by giving a foreign Key it fires a GET request to
/users?filter=[{"property":"group_id","value":"453490sdkjskldfjlskdjf","exactMatch":true}]
But this is MySQL kind of association.
How do I solve this to adapt to mongo style of associations?
SO I basically want this to happen. Right now when I call
groups.users().load() it fires a GET request to the Users proxy with the filter params like this
/users?filter=[{"property":"group_id","value":"453490sdkjskldfjlskdjf","exactMatch":true}]. But I don't have group_id in users! So it has to query the users proxy based on the ObjectId it finds inside the users attribute of the group object.
As this is very common in Document based DB, Is this possible by default ? Am I missing something ?
Thanks.
Relationship 1:many in Ext is not implemented the same way as in DBMS. In DBMS we have two tables (a construct similar to store in Ext) and the relationship is defined by foreign keys that link records between tables.
In Ext, we (can) have a store on 1-side (Groups) but we do not have one single store for many-side (Users). Instead, each record of Groups contains a store for Users. It is not exactly a record field for the store but Ext defines a getter.
In your case group.users() returns a store with users that belong to that specific group. Ext behaves exactly same as with any other store when you try to load it: group.users().load() - it only adds filter for that specific foreign key so that you don't need to do it manually.
Related
First let me explain schema of my collections.
I have 3 collections
company,deal,price
I want to use information from all three collection and make a single reactive,responsive table. Here is the image
Now the schema for price collection is like this
{
"_id" : "kSqH7QydFnPFHQmQH",
"timestamp" : ISODate("2015-10-11T11:49:50.241Z"),
"dealId" : "X5zTJ2y675PjmaLMx",
"deal" : "Games",
"price" : [{
"type" : "worth",
"value" : "Bat"
}, {
"type" : "Persons",
"value" : 4
}, {
"type" : "Cost",
"value" : 5
}],
"company" : "Company1"
}
Schema for company collection is
{
"_id" : "da2da"
"name" : "Company1"
}
Schema for deal collection is
{
"_id" : "X5zTJ2y675PjmaLMx",
"name" : "Games"
}
For each company there will be 3 columns added in table(worth,persons,cost)
For each deal there will be a new row in table.
As the information is coming from 3 collections into a single table. First I want to ask is it wise to make a table from 3 different collections? If yes how could I do that in blaze?
If no. Then I will have to make table from price collection only . What should be schema of this collection in best way.
P.S in both cases I want to make table reactive.
Firstly, I recommend reywood:publish-composite for publishing related collections.
Secondly there is no intrinsic problem in setting up a table like this, you'll first figure out which collection to loop over with your {{#each}} in spacebars and then you'll define helpers that return the values from the related collections to your templates.
As far as your schema design, the choice as to whether to use nesting within a collection vs. using an entirely separate collection is typically driven by size. If the related object is overall "small" then nesting can work well. You automatically get the nested object when you publish and query that collection. If otoh it's going to be "large" and/or you want to avoid having to update every document when something in the related object changes then a separate collection can be better.
If you do separate your collections then you'll want to refer to objects from the other collection by _id and not by name since names can easily change. For example in your price collection you'd want to use companyId: "da2da" instead of company: "Company1"
I'm using passport.js to store my users into my mongodb. A user object looks like this
{
"_id" : ObjectId("54893faf0907a100006341ee"),
"local" : {
"password" : [encrypted password],
"email" : "johnsmith#domain.com"
},
"__v" : 0
}
In a mongodb shell how would I go about listing all the emails? I'm finding it difficult to do this as my data sits two level deep within the object. Cheers!
You can use distinct to get a list of a field's distinct values in the collection, using dot notation to reference the embedded field:
db.users.distinct('local.email')
I have two MongoDB collections user and customer which are in one-to-one relationship. I'm new to MongoDB and I'm trying to insert documents manually although I have Mongoose installed. I'm not sure which is the correct way of storing document reference in MongoDB.
I'm using normalized data model and here is my Mongoose schema snapshot for customer:
/** Parent user object */
user: {
type: Schema.Types.ObjectId,
ref: "User",
required: true
}
user
{
"_id" : ObjectId("547d5c1b1e42bd0423a75781"),
"name" : "john",
"email" : "test#localhost.com",
"phone" : "01022223333",
}
I want to make a reference to this user document from the customer document. Which of the following is correct - (A) or (B)?
customer (A)
{
"_id" : ObjectId("547d916a660729dd531f145d"),
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street",
"user" : ObjectId("547d5c1b1e42bd0423a75781")
}
customer (B)
{
"_id" : ObjectId("547d916a660729dd531f145d"),
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street",
"user" : {
"_id" : ObjectId("547d5c1b1e42bd0423a75781")
}
}
Remember these things
Embedding is better for...
Small subdocuments
Data that does not change regularly
When eventual consistency is acceptable
Documents that grow by a small amount
Data that you’ll often need to perform a second query to fetch Fast reads
References are better for...
Large subdocuments
Volatile data
When immediate consistency is necessary
Documents that grow a large amount
Data that you’ll often exclude from the results
Fast writes
Variant A is Better.
you can use also populate with Mongoose
Use variant A. As long as you don't want to denormalize any other data (like the user's name), there's no need to create a child object.
This also avoids unexpected complexities with the index, because indexing an object might not behave like you expect.
Even if you were to embed an object, _id would be a weird name - _id is only a reserved name for a first-class database document.
One to one relations
1 to 1 relations are relations where each item corresponds to exactly one other item. e.g.:
an employee have a resume and vice versa
a building have and floor plan and vice versa
a patient have a medical history and vice versa
//employee
{
_id : '25',
name: 'john doe',
resume: 30
}
//resume
{
_id : '30',
jobs: [....],
education: [...],
employee: 25
}
We can model the employee-resume relation by having a collection of employees and a collection of resumes and having the employee point to the resume through linking, where we have an ID that corresponds to an ID in th resume collection. Or if we prefer, we can link in another direction, where we have an employee key inside the resume collection, and it may point to the employee itself. Or if we want, we can embed. So we could take this entire resume document and we could embed it right inside the employee collection or vice versa.
This embedding depends upon how the data is being accessed by the application and how frequently the data is being accessed. We need to consider:
frequency of access
the size of the items - what is growing all the time and what is not growing. So every time we add something to the document, there is a point beyond which the document need to be moved in the collection. If the document size goes beyond 16MB, which is mostly unlikely.
atomicity of data - there're no transactions in MongoDB, there're atomic operations on individual documents. So if we knew that we couldn't withstand any inconsistency and that we wanted to be able to update the entire employee plus the resume all the time, we may decide to put them into the same document and embed them one way or the other so that we can update it all at once.
In mongodb its very recommended to embedding document as possible as you can, especially in your case that you have 1-to-1 relations.
Why? you cant use atomic-join-operations (even it is not your main concern) in your queries (not the main reason). But the best reason is each join-op (theoretically) need a hard-seek that take about 20-ms. embedding your sub-document just need 1 hard-seek.
I believe the best db-schema for you is using just an id for all of your entities
{
_id : ObjectId("547d5c1b1e42bd0423a75781"),
userInfo :
{
"name" : "john",
"email" : "test#localhost.com",
"phone" : "01022223333",
},
customerInfo :
{
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street",
},
staffInfo :
{
........
}
}
Now if you just want the userinfo you can use
db.users.findOne({_id : ObjectId("547d5c1b1e42bd0423a75781")},{userInfo : 1}).userInfo;
it will give you just the userInfo:
/* 0 */
{
"name" : "john",
"email" : "test#localhost.com",
"phone" : "01022223333"
}
And if you just want the **customerInfo ** you can use
db.users.findOne({_id : ObjectId("547d5c1b1e42bd0423a75781")},{customerInfo : 1}).customerInfo;
it will give you just the customerInfo :
/* 0 */
{
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street"
}
and so on.
This schema has the minimum hard round-trip and actually you are using mongodb document-based feature with best performance you can achive.
I have two models 'User' and 'point'.
i need when i create a user, with an id like 2juifdsf7tdf65sd67, the same id go to 'point' model.
An ID for the two models sometime.
Its possible?
how to do this in an alternative method?
Update:
when i create the 'User', i need him to get an 'point', the model 'point' get the same id of the user, all in a html view page. but when a create a new user and a point, the id is different, is not the same.
If you put User and Point in 2 different collection you can use same id for those and of couse you should set _id manually
db.User.insert(
{
_id : 100,
...
})
db.Point.insert(
{
_id : 100,
...
})
_id could be number, string and ...
But I think the better solution for u is using reference id
db.User.insert(
{
_id : 100,
point_Id: 13588,
...
})
db.Point.insert(
{
_id : 13588,
...
})
I am getting JSON objects through an external API in node.js and want to store them in MongoDB. I defined a model like this:
var Product = new Schema({
id: ObjectId,
name: String});
And now I'm trying to store an object:
JSONProduct = { id: 1234, name: 'The Foo Bar' };
product = new Product(JSONProduct);
product.save();
The object is stored fine in the "products" collection, but the id from the JSONProduct is replaced by a MongoDB created value:
{ "id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
The main reason why I want to use my Product id over the MongoDB created one is, that I want to prevent duplicate entries for products. I get the JSON Product objects through a cronjob triggered call on an external API, including already existing ones. Maybe there is another, better way to do this?
You are defining an field as an ObjectID, but you are assigning a Number to it. To create an ObjectID you need to do something like:
new ObjectId('something');
However, in your case this is probably not the best idea. Define your model like this:
var Product = new Schema({
external_id: {type: Number, unique: true},
name: {type: String},
});
You can specify unique on a field to create a unique index for that field.
In the question you've mentioned,
The object is stored fine in the "products" collection, but the id from the JSONProduct is replaced by a MongoDB created value:
{ "id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
But I think the it is created as:
{ "_id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
Also, you can pass in your product id to field by name "_id", then mongo will not create any separate IDs and it'll not accept duplicate values and it'll have indexing automatically for that field.
But make sure you push unique values of product id to _id.