Not giving Parent data from Child in association in extjs - extjs

Hope you are doing good.
I am new in extjs4 and working on sample example of association.
I have 2 different class User and Diploma
In relation, I have defined.
User hasMany Diplomas, and Diplomas belongsTo User
My models are as belows
User.js
Ext.define('MyApp.model.User', {
extend : 'Ext.data.Model',
idProperty : 'userId',
fields : [{
name : 'userId',
type : 'integer'
}, {
name : 'userName',
type : 'string',
}],
hasMany : {
model : 'MyApp.model.Diploma',
name : 'diplomas',
},
});
Diploma.js
Ext.define('MyApp.model.Diploma', {
extend : 'Ext.data.Model',
idProperty : 'diplomaId',
fields : [{
name : 'diplomaId',
type : 'integer'
}, {
name : 'diplomaName',
type : 'string',
}, {
name : 'userId',
type : 'integer'
}],
associations : [{
model : 'MyApp.model.User',
name : 'user',
type : 'belongsTo'
}]
});
=====================
My Stores are as below.========================
Diploma.js
Ext.define('MyApp.store.Diploma', {
extend : 'Ext.data.Store',
model : 'MyApp.model.Diploma',
autoLoad : true,
listeners : {
'load' : {
fn : function(store, records, success, operation) {
console.log('Diplomas are loaded');
}
}
}
});
User.js
Ext.define('MyApp.store.User', {
extend : 'Ext.data.Store',
model : 'MyApp.model.User',
requires:['Ext.data.proxy.LocalStorage'],
autoLoad : true,
listeners : {
'load' : {
fn : function(store, records, success, operation) {
console.log('User is loaded');
}
}
},
data : [{
userId : 1,
userName : 'Rishabh Shah',
diplomas:{
userId : 1,
diplomaId:1,
diplomaName:'IT'
}
}, {
userId : 2,
userName : 'Rakesh Shah',
diplomas:{
userId : 2,
diplomaId:2,
diplomaName:'CE'
}
}, {
userId : 3,
userName : 'Rashmin Shah'
}],
proxy:{
type:'memory',
reader:{
root:'data'
}
}
});
I can get diploma from user like that and can get result
Ext.getStore("User").getAt(0).diplomasStore.getAt(0)
but, when I try to do like
Ext.getStrore("Diploma") or Ext.getStrore("Diploma").getAt(0)
I don't get anything. items contains nothing...
How can I get user from diploma.
and One more thing....if I don't write proxy in my Diploma model..
it gives me an error like this..
Ext.data.proxy.Server.buildUrl(): You are using a ServerProxy but have not supplied it with a url.
Please guide me.
Thanks.
Thanks for your reply..#john..I can get diplomas from User..
I wanted to get user from diplomas...I tried it myself..and found solution...
I will have following json.
[
{
"depId": 1,
"depName": "CE",
"employees": [
{
"empId": 1,
"firstName": "Rishabh",
"lastName": "Shah"
}, {
"empId": 2,
"firstName": "Smit",
"lastName": "Patel"
}
]
}, {
"depId": 2,
"depName": "IT",
"employees": [
{
"empId": 1,
"firstName": "Parag",
"lastName": "Raval"
}, {
"empId": 2,
"firstName": "Rakesh",
"lastName": "Prajapati"
}
]
}, {
"depId": 3,
"depName": "EE",
"employees": [
{
"empId": 1,
"firstName": "Parag EE",
"lastName": "Raval EE"
}, {
"empId": 2,
"firstName": "Rakesh EE",
"lastName": "Prajapati EE"
}
]
}, {
"depId": 4,
"depName": "EC",
"employees": [
{
"empId": 1,
"firstName": "Parag EC",
"lastName": "Raval EC"
}, {
"empId": 2,
"firstName": "Rakesh EC",
"lastName": "Prajapati EC"
}
]
}, {
"depId": 5,
"depName": "Chemial E",
"employees": [
{
"empId": 1,
"firstName": "Parag",
"lastName": "Raval"
}, {
"empId": 2,
"firstName": "Rakesh",
"lastName": "Prajapati"
}
]
}, {
"depId": 6,
"depName": "ME",
"employees": [
{
"empId": 1,
"firstName": "Parag",
"lastName": "Raval"
}, {
"empId": 2,
"firstName": "Rakesh",
"lastName": "Prajapati"
}
]
}, {
"depId": 7,
"depName": "Civil Engineer",
"employees": [
{
"empId": 1,
"firstName": "Parag",
"lastName": "Raval"
}, {
"empId": 2,
"firstName": "Rakesh",
"lastName": "Prajapati"
}
]
}
]
and I will use model.getAssociatedData().user as per my requirement
where model is my record of child class and user is my parent class..
and I was using proxy in my Diploma Model which was not requierd....so, was getting
Ext.data.proxy.Server.buildUrl(): You are using a ServerProxy but have not supplied it with a url.
above mentioned error.
Thanks All ! :)

What exactly isn't working? Have you been able to use the magic methods e.g., User.diplomas()? As #VDP stated, the store created for the Association is a normal Ext.data.Store scoped to the set of data for the parent model (in this case, User). That is to say, if you have a User model with the id of 1, calling the method User.diplomas() will return a Ext.data.Store filtered to contain only Diploma's with a user_id of 1.
This is very important to understand! If you do not specify the foreignKey property in a hasMany association, it will default to the lowercased name of the owner model plus "_id", You should amend your User model's hasMany association as so:
Ext.define('MyApp.model.User', {
/** Model Definition */
hasMany : {
model : 'MyApp.model.Diploma',
name : 'diplomas',
foreignKey : userId /** This is what you're missing */
}
});
Perhaps you will find this blog post useful? http://extjs-tutorials.blogspot.com/2012/05/extjs-hasmany-relationships-rules.html
Some important tips from the blog post (in case the link dies at some point)
Always put your Proxies in your Models, not your Stores, unless you
have a very good reason not to *
Always require your child models if using them in hasMany
relationships. **
Always use foreignKey if you want to load the children at will
Always use associationKey if you return the children in the same
response as the parent
You can use both foreignKey and associationKey if you like
Always name your hasMany relationships
Always use fully qualified model names in your hasMany relationship
Consider giving the reader root a meaningful name (other than "data")
The child model does not need a belongsTo relationship for the
hasMany to work
*The store will inherit its model's proxy, and you can always override it
**To make it easy, and avoid potential circular references, you can require them in app.js
Credit: Neil McGuigan (http://www.blogger.com/profile/14122981831780837323)

Related

How to join and group user list results with values from array in another collection? [duplicate]

This question already has answers here:
How do I perform the SQL Join equivalent in MongoDB?
(19 answers)
$lookup on ObjectId's in an array
(7 answers)
Closed 3 years ago.
I am new to MongoDB and am trying to retrieve a list of users that contains their user roles which are stored in the DB as a separate collection to the users collection.
I have a users collection, sample document below:
/* 1 */
{
"_id": "cf67e695-ea52-47a8-8e42-b95b863a2b69",
"DateCreated": ISODate("2018-11-11T21:41:37.125Z"),
"Email": "user#email.com",
"FirstName": "John",
"LastName": "Does",
"Language": "en",
"TimeZoneId": null,
"Roles": [
"c2ee344f-48b7-4c46-9392-853c6debd631",
"ada94631-af8c-43e9-a031-de62ffae1d20"
],
"Status": 0
}
I also have a Roles collection, sample document below:
{
"_id": "c2ee344f-48b7-4c46-9392-853c6debd631",
"DateCreated": ISODate("2018-11-14T10:58:27.053Z"),
"Name": "Administrator 2",
"Description": " View only but able to manage their own users (credentials). They do have update capabilities"
}
What I want is to retrieve a list that shows the user friendly name of the role and not the _id value of each role that is currently stored against the User Profile. I'm close but not quite there.
Using the following, I am able to get the results of the Roles list but ONLY the role Names. What I want is the full User profiles with the user friendly names attached with each document. Here is my syntax so far:
db.Users.aggregate([
{
$match: {
"Email": /#email.com/
}
},
{
$project: {
_id: 1,
Email: 1,
FirstName: 1,
Roles: 1
}
},
{
$unwind: {
path: "$Roles"
}
},
{
$lookup: {
from: "Roles",
localField: "Roles",
foreignField: "_id",
as: "Roles"
}
},
{
$group: {
_id: "$_id",
Roles: {
$push: "$Roles.Name"
}
}
}
])
For whatever reason I am not getting the Email, FirstName and LastName fields returned in the results. All I get currently is:
{
"_id": "639ba2b6-fc80-44f4-8ac0-0a92d61099c4",
"Roles": [
[
"Administrator 2"
],
[
"Administrators"
]
]
}
I would like to get something like:
{
"_id": "cf67e695-ea52-47a8-8e42-b95b863a2b69",
"DateCreated": ISODate("2018-11-11T21:41:37.125Z"),
"Email": "user#email.com",
"FirstName": "John",
"LastName": "Does",
"Language": "en",
"TimeZoneId": null,
"Roles": [
"Administrators",
"Administrator 2"
],
"Status": 0
}
Any help, much appreciated!
You have to include those fields in your $group pipeline, Please just update your $group with below:
$group: {
_id: "$_id",
FirstName: {$first:"$FirstName"},
Email: {$first:"Email"},
Roles: {
$push: "$Roles.Name"
}
}
you can add more fields you need using $first in $group. I have tried with the given sample document and its working for me.
Add this code
db.users.aggregate([
{
$unwind: "$Roles"
},
{
$lookup:
{
from: "roles",
localField: "_id",
foreignField: "Roles",
as: "Roles"
}
}
]).exec((err, result) => {
console.log(result);
})

ExtJS 6 inherited hasMany-Relation nested loading

I try to setup a hasMany relationship and want load my main entity with all the associated models in a single request.
But that seems not to work with "hasMany" relations that is inherited.
I have a BaseModel that defines all relations and fields and a "normal" model that defines the proxy to load from.
These are my (relevant) models:
Ext.define('MyApp.model.BaseUser', {
"extend": "Ext.data.Model",
"uses": [
"MyApp.model.UserEmail",
"MyApp.model.Account"
],
"fields": [
{
"name": "name"
},
{
"name": "accountId",
"reference": {
"type": "MyApp.model.Account",
"role": "account",
"getterName": "getAccount",
"setterName": "setAccount",
"unique": true
}
}
]
"hasMany": [
{
"name": "emails",
"model": "MyApp.model.UserEmail"
}
],
});
Ext.define('MyApp.model.User', {
extend: "MyApp.model.BaseUser",
proxy: {
type: 'rest',
url : '/api/user',
reader: {
type: 'json',
rootProperty: 'data',
}
}
});
Ext.define('MyApp.model.UserEmail', {
extend: 'Ext.data.Model',
"fields": [
{
"name": "id",
"type": "int"
},
{
"name": "email",
"type": "string"
},
],
proxy: {
type: 'rest',
url : '/api/user/email',
reader: {
type: 'json',
rootProperty: 'data',
}
}
});
// MyApp.model.Account looks like MyApp.model.UserEmail
This is my server's response:
{
data: [
{
name: 'User Foo'
accountId: 50
account: {
id: 50,
balance: 0
},
emails: [
{
id: 70,
email: 'hello#world.de'
}
]
}
]
}
The "account" relation is working on the "normal" User Model and I can access it via the auto-generated method user.getAccount() as I expected.
Now I tried to access the users emails with the auto-generated methods:
// user is of 'MyApp.model.User'
user.emails(); // store
user.emails().first(); // null
user.emails().count(); // 0
It seems that the "emails"-relation models were not loaded into my user model. Am I accessing them the right way?
I can access them via user.data.emails. But this is an array of plain objects, not of UserEmail-Objects.
Can anyone give me some advice? Is nested loading supported with keyless associations?
Kind regards,
czed
Edit:
Clearified what I ment.
It should work. Here's a working fiddle. Check console for nested loaded data.

Dynamically generated metadata does not display grid

The following data is being used to load and display a grid dynamically. The only difference between the two grids is that the first reader takes in the data below as is, but the second grid only knows about the data and the metaData will be generated on the fly. I placed stubs for the fields and columns as this is not the issue and I haven't decided on how I will generate the data yet.
Both of the readers eventually pass the data below to the JsonReader's readRecords()' function via this.callParent([data]);, but the second one does not display the data. The data is there, but I am not sure why it does not display?
There are two links to demos below. The first is a JSFiddle that loads from memory and the second is a Sencha Fiddle that loads through AJAX.
Snippet
var rawFields = [
{ "name": "year", "type": "int" },
{ "name": "standard", "type": "string" },
{ "name": "bitRate", "type": "float" }
];
var rawColumns = [
{ "text" : "Year", "dataIndex" : "year", "flex" : 1 },
{ "text" : "Standard", "dataIndex" : "standard", "flex" : 1 },
{ "text" : "Bit/Sec", "dataIndex" : "bitRate", "flex" : 1 }
];
Ext.define('Example.reader.DynamicReader', {
extend : 'Ext.data.reader.Json',
alias : 'reader.dynamicReader',
readRecords : function(data) {
var response = {
data: data,
metaData : this.createMetaData(data),
success: true
};
console.log(response);
return this.callParent([response]);
},
createMetaData : function(data) {
return {
idProperty : "id",
fields : rawFields, // These will eventually be generated...
columns : rawColumns // These will eventually be generated...
};
}
});
Data
{
"data": [
{
"id": 0,
"year": 1997,
"standard": "802.11",
"bitRate": 2000000
},
{
"id": 1,
"year": 1999,
"standard": "802.11b",
"bitRate": 11000000
},
{
"id": 2,
"year": 1999,
"standard": "802.11a",
"bitRate": 54000000
},
{
"id": 3,
"year": 2003,
"standard": "802.11g",
"bitRate": 54000000
},
{
"id": 4,
"year": 2007,
"standard": "802.11n",
"bitRate": 600000000
},
{
"id": 5,
"year": 2012,
"standard": "802.11ac",
"bitRate": 1000000000
}
],
"metaData": {
"idProperty": "id",
"fields": [
{
"name": "year",
"type": "int"
},
{
"name": "standard",
"type": "string"
},
{
"name": "bitRate",
"type": "float"
}
],
"columns": [
{
"text": "Year",
"dataIndex": "year",
"flex": 1
},
{
"text": "Standard",
"dataIndex": "standard",
"flex": 1
},
{
"text": "Bit/Sec",
"dataIndex": "bitRate",
"flex": 1
}
],
"success": true
}
}
Demos
The following examples both achieve the same thing, so the only difference is the loading of the data.
Loading from Memory
http://jsfiddle.net/MrPolywhirl/zy4z5z8a/
Loading from AJAX
https://fiddle.sencha.com/#fiddle/d3l
I figured out the answer. I needed to specify a root value for the reader so that the data can be mapped properly.
Ext.onReady(function() {
Ext.widget("dynamicGrid", {
title: 'WiFi LAN Data Rates [Dynamic]',
renderTo: Ext.get('example-grid-dynamic'),
readerType: 'dynamicReader',
// This need to match the 'data' key specified in the `response` object
// that was created in readRecords().
readerRoot: 'data',
data : rawData
});
});
The documentation for root notes that the root property has to map to the data portion of the response.
Documentation for Json.root:
Ext.data.reader.Json.root
root : String
The name of the property which contains the data items corresponding to the Model(s) for which this Reader is configured. For JSON reader it's a property name (or a dot-separated list of property names if the root is nested). For XML reader it's a CSS selector. For Array reader the root is not applicable since the data is assumed to be a single-level array of arrays.

Can you define a hasMany relationship with a HashMap in an extJs model?

I have some json data with the following format:
{
"id":1,
"personMap":{
"president":{"firstname":"Sookie","lastname":"Stackhouse"},
"vicepresident":{"firstname":"Eric","lastname":"Northman"},
"treasurer":{"firstname":"Alcide","lastname":"Herveaux"}
}
}
How do I define my model so that the values in the map are loaded with the correct object type? Is that possible?
The following will load the data but the values are not typed as 'Person' objects:
Ext.define('Committee', {
extend: 'Ext.data.Model',
fields: [ 'id', 'personMap' ]
});
The following would expect personMap to be an array not a map:
Ext.define('Committee', {
extend: 'Ext.data.Model',
fields: [ 'id' ],
hasMany: [{
model: 'Person',
name: 'personMap'
}]
});
Ext.define('Person', {
extend: 'Ext.data.Model',
fields: [ 'firstname', 'lastname' ]
});
The hasMany config only applies to arrays. Changing the data structure to,
{
"id": 1,
"personMap": [
{
"firstname": "Sookie",
"lastname": "Stackhouse",
"title": "president"
},
{
"firstname": "Eric",
"lastname": "Northman",
"title": "vicepresident"
},
{
"firstname": "Alcide",
"lastname": "Herveaux",
"title": "treasurer"
}
]
}
will do the trick, but if that's not an option then the hasMany config cannot be used.

How to auto-create many-to-many relations from initial JSON with Backbone Relational?

The example from docs about many-to-many relationship supposes that companies would be added after the person was already created.
However, what if the person data comes from server with a list of companies (companies' ids) already?
Is it possible to modify the example so that the following code (or smt. similar) would be possible:
// somewhere before we have a collection of companies defined like this:
// [{id: 1, name: 'ibm'}, {id: 2, name: 'apple'}]
// and than we do:
paul = new Person({
name: 'Paul',
jobs: [1, 2]
})
paul.get('jobs').at(0).get('name') // 'ibm'
When trying to achieve this the same way I'd do with one-to-many relations, I fail:
Companies = Backbone.Collection.extend({model: Company})
companies = new Companies([{id: 1, name: 'ibm'}, {id: 2, name: 'apple'}])
john = new Person({
name: 'John',
jobs: [1]
})
john.get('jobs').toJSON() // []
companies.get(1).get('employees').toJSON() // []
Here's the fiddle you can play with: http://jsfiddle.net/ymr5Z/
Your MAIN problem is that you are trying to add Jobs by ID. You never created any job object though let alone set their id! You only created the companies.
A better way to go about adding jobs is to have an addJob() function which you give a company ID (or company) and it creates the Job model for you.
Full Code to fit your example
and specifically:
var Person = Backbone.RelationalModel.extend({
relations: [{
type: 'HasMany',
key: 'jobs',
relatedModel: Job,
reverseRelation: {
key: 'person'
//includeInJSON: false //if you don't want to show person
}
}],
addJob: function (company) {
this.get('jobs').add(new Job({
company: company
}));
}
});
paul.addJob(1);
paul.addJob(2);
Works perfectly. You might also want to set an includeInJSON to false for your reverse relationship on the Job to exclude the person!
[{
"company": {
"id": 1,
"name": "ibm",
"employees": [null]
},
"person": {
"name": "Paul",
"jobs": [null, {
"company": {
"id": 2,
"name": "apple",
"employees": [null]
}
}]
}
}, {
"company": {
"id": 2,
"name": "apple",
"employees": [null]
},
"person": {
"name": "Paul",
"jobs": [{
"company": {
"id": 1,
"name": "ibm",
"employees": [null]
}
},
null]
}
}]

Resources