Breeze: getting collection of results that are wrapped in meta data object - angularjs

I am attempting to use Breeze with AngularJS and a Web API back end which returns data in the following format:
API response format:
{
Count: 123,
Items: [
{
CustomerID: 1,
FirstName: "John",
Surname: "Smith",
// etc..
},
{
CustomerID: 2,
FirstName: "Bill",
Surname: "Jones",
// etc..
},
{
// 23 more Customer records...
}
],
NextPageLink: "http://localhost/web/api/customers?$skip=25"
}
I have manually set up the Customer entity in the metaDataStore following the example on the Breeze.js website http://www.breezejs.com/documentation/metadata-hand-depth:
function addCustomer() {
addType({
shortName: "Customer",
defaultResourceName: "customers",
dataProperties: {
CustomerID: { type: ID, isPartOfKey: true },
FirstName: { max: 50 },
Surname: { max: 50 },
// a bunch more properties
}
});
}
My code to query the "customers" endpoint looks like this:
function getCustomers(){
var customers = manager.getEntities('Customer');
return breeze.EntityQuery.from('customers')
.using(manager).execute()
.then(function(data){
return data.results; // breakpoint here is reached
});
}
The query successfully executes, as when I put a breakpoint where indicated, the data object is there but the data.results property is an array containing what looks like a single Customer entity that is empty. See screenshot:
I suspect that this is due to the fact the the back end is returning the collection as the Items property of a wrapper object.
My question then is: assuming I am unable to change the response from the back end API, how do I tell Breeze that my Customer entities are actually contained in the results.Items property?

You can build your own custom JsonResultsAdapter to do this.
See http://www.breezejs.com/documentation/mapping-json for more details.
We also have a sample that shows a custom adapter in action with a 3rd party back end.
Hope this helps.

Related

Properties not changing on the DOM after a GET request

I am working on a component to render user details. The details are fetched from an API request and properties are updated but these changes are not reflected on the DOM.
The company I work for is still using Polymer 1.2 and I am having difficulty finding and understanding the documentation. Do I need to make the get request from the parent component or is it possible to do this directly inside the component? There is something fundamental I am not grasping about this and wondering if someone could shed some light on it for me.
Thank you.
Snippet from the template:
<p>{{i18n.GLOBAL_USERNAME}} - [[username]]</p>
<p>{{i18n.GLOBAL_FIRSTNAME}} - [[firstname]]</p>
<p>{{i18n.GLOBAL_LASTNAME}} - [[lastname]]</p>
<p>{{i18n.GLOBAL_EMAIL}} - [[email]]</p>
<p>{{i18n.GLOBAL_NUMBER}} - [[number]]</p>
Snippet from the polymer functions:
Polymer({
is: 'my-component',
properties: {
username: {
type: String,
value: "n/a",
},
firstname: {
type: String,
value: "n/a"
},
lastname: {
type: String,
value: "n/a"
},
email: {
type: String,
value: "n/a"
},
number: {
type: String,
value: "n/a"
},
},
ready: function () {
var user = app.auth.hasSession()
if (user !== null) {
app.getUserInfo(user.user_id, this._getUserSuccessful, this._getUserFail);
}
},
_getUserSuccessful: function (res) {
this.username = res.user.user_id
this.firstname = res.user.firstname
this.lastname = res.user.lastname
this.email = res.user.email
this.number = res.user.phone_number
console.log("got user details")
},
_getUserFail: function () {
console.log("failed to get user details")
},
});
You need to use Polymer setter methods instead of plain assignment.
Here's an example:
_getUserSuccessful: function (res) {
this.set('username', res.user.user_id)
this.set('firstname', res.user.firstname)
this.set('lastname', res.user.lastname)
this.set('email', res.user.email)
this.set('number', res.user.number)
console.log("got user details")
},
Using setter and/or array mutator methods is required for data-bound properties otherwise Polymer can't know that something has changed in order to update the bindings.
I'd really suggest you read the whole Data system concepts article before moving forward with doing any kind of work with Polymer 1.x.

Kendo DataSource reading from Async/await method which uses Axios to fetch data

Using React with TypeScript
Please could somebody provide an example of how I might be able to use a Kendo DataSource to read from a method which internally uses Axios to prod an external API for JSON data..? I must have flown through 20 different versions of this code trying different approaches, nothing seems to fit...
All I'm trying to do currently is supply a Kendo ComboBox with an array of {id: number, name: string}
Very basic stuff at the moment, but I do have to use a similar approach to this later on with a Kendo Grid which handles server side sorting and pagination so I'd like to get this working now then that should be somewhat easier later on...
The reason I want to use Axios is because I've written an api.ts file that appends appropriate headers on the gets and posts etc and also handles the errors nicely (i.e. when the auth is declined etc...)
A basic example of what I'm trying, which isn't working is this: -
public dataSource: any;
constructor(props: {}) {
super(props);
this.dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: function() {
return [{ id: 1, name: "Blah" }, { id: 2, name: "Thing" }];
}.bind(this)
},
schema: {
model: {
fields: {
id: { type: "number" },
name: { type: "string" }
}
}
}
});
}
<ComboBox
name="test"
dataSource={this.dataSource}
placeholder={this.placeholder}
dataValueField="id"
dataTextField="name"
/>
Anybody got any thoughts on this please? :)
Easy fix in the end...
this.dataSource = new kendo.data.DataSource({
transport: {
read: function(options: any) {
options.success([{ id: 1, name: "Blah" }, { id: 2, name: "Thing" }]);
}.bind(this)
},
schema: {
model: {
fields: {
id: { type: "number" },
name: { type: "string" }
}
}
}
});
2 things were wrong..
Removed the type: "odata",
and
Added the usage of options in
All working fine now with the async await function also, just passing the data into the options.success in the .then on the promise. Job done :-)

Is there any way to .populate() a mongoDB document with mongoose and save the populated object back into the model? [duplicate]

This question already has answers here:
Mongoose populate vs object nesting
(1 answer)
MongoDB relationships: embed or reference?
(10 answers)
Closed 5 years ago.
I have a question, wondering if there is any way to persist the returned document when using the Mongoose .populate() function by saving it back to the model. Also some questions on how to structure things. Here are my schemas:
var clientSchema = new Schema({
phone: String,
email: String
},
);
var menuSchema = new Schema({
itemName: String,
itemPrice: Number,
});
var transactionSchema = new Schema ({
createdBy: { type: Schema.ObjectId, ref: 'Client'},
items: [{ type: Schema.ObjectId, ref: 'Menu' }],
});
var Menu = mongoose.model('Menu', menuSchema);
var Client = mongoose.model('Client', clientSchema);
var Transaction = mongoose.model('Transaction', transactionSchema);
When I create a new Transaction with a POST request, I populate it and return the populated Transaction as a response:
{
"_id": "5a0bde94f4434c0a604341d2",
"createdBy": {
"_id": "5a0a8a3f9c348f0998ba8c2c",
"phone": "1234567890",
"email": "some#thing.com"
},
"__v": 0,
"items": [{ Many Menu objects }]
}
However, when I query the DB again with GET, I get this:
{
"_id": "5a0bde94f4434c0a604341d2",
"createdBy": "5a0a8a3f9c348f0998ba8c2c",
"__v": 0,
"items": [Array of ObjectIds]
}
I can't use .save() because the original schema only accepts ObjectId, not an entire Object.
I noticed that when I made my schema include SubDocuments, I did not really need to use the .populate() function. I simply pushed an object into the array, and it would be there when queried.
var transactionSchema = new Schema ({
createdBy: { type: Schema.ObjectId, ref: 'Client'},
items: [menuSchema], // Sub Doc
});
MongoDB Docs say creating large mutable arrays is a bad design. I could see some transactions having 50 or 100 objects. I can see this being more of a problem if I use subDocuments because file size , but I could also imagine that doing a .populate() on an array of 100 object IDs may be expensive.
I need to update the items array in the transaction schema every time the client registers an onclick function. I need to re-render that to the client, which involves a single PUT request per click. But I have to parse that array with each click, one by one. If I'm doing a .populate() on every single item in the array...that's not great. But using subDocuments would increase the filesize of the database.
I previously had a simpler schema, but thought that passing by reference would increase the integrity of the prices being rendered. Is it better to just have an array of Objects and push into that?
var transactionSchema = new Schema ({
createdBy: { type: Schema.ObjectId, ref: 'Client'},
items: [{
name: {type: String},
price: {type: Number}
}]
});

Meteor, MongoDB get part of array through subscription

I have a question about how to just get a certain element of an array using MongoDB and MeteorJS. I have the following schema for the user document:
bankList:[
{
id: "34567890987654345678",
name: "xfgchjbkn",
type: "credit"
},
{
id: "09876543456789098767"
name: "65789876t8",
type: "debit"
}
]
I first subscribe to only part of the fields in the array, specifically I gather a list of all the ids. Then I have an edit screen that should subscribe to all of the fields for a specific element in the array with a matching id. I do not want to expose the rest of the array just the single element. Currently, I use the following to first gather a list of just the ids:
Meteor.users.find({_id: this.userId},
{fields:{'bankList.id': 1}});
And the following publication-subscription method to get just a specific element's information:
Publication:
Meteor.publish("userBankAdvanced", function(bankId){
check(bankId,String);
if(this.userId){
return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {'bankList.$': 1});
}else{
this.ready();
}
});
Subscription:
this.route('edit_account', {
path: '/edit/account/',
waitOn: function(){
if(Session.get("bankId")){
return Meteor.subscribe('userBankAdvanced',Session.get("bankId"));
}
return null;
},
data: function(){
if(Session.get("bankId")){
return Meteor.users.findOne();
}
return null;
},
onBeforeAction: function(){
beforeHooks.isRevise(Session.get("bankId"));
}
});
The subscription method returns all of the elements of the array with all of the information.
I want, for example, just this (not the entire list with all of the information):
bankList:[
{
id: "34567890987654345678",
name: "xfgchjbkn",
type: "credit"
}]
It looks like you're just missing the "fields" specifier in your "userBankAdvanced" publish function. I wrote a test in meteorpad using your example and it seems to work fine. The bank id is hardcoded for simplicity there.
So instead of
return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {'bankList.$': 1});
try using
return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {fields: {'bankList.$': 1}});
No luck, in meteor the "fields" option works only one level deep. In other words there's no builtin way to include/exclude subdocument fields.
But not all is lost. You can always do it manually
Meteor.publish("userBankAdvanced", function (bankId) {
var self = this;
var handle = Meteor.users.find({
_id: self.userId, "bankList.id": bankId
}).observeChanges({
added: function (id, fields) {
self.added("users", id, filter(fields, bankId));
},
changed: function (id, fields) {
self.changed("users", id, filter(fields, bankId));
},
removed: function (id) {
self.removed("users", id);
},
});
self.ready();
self.onStop(function () {
handle.stop();
});
});
function filter(fields, bankId) {
if (_.has(fields, 'bankList') {
fields.bankList = _.filter(fields.bankList, function (bank) {
return bank.id === bankId;
});
}
return fields;
}
EDIT I updated the above code to match the question requirements. It turns out though that the Carlos answer is correct as well and it's of course much more simple, so I recommend using that one.

backbonejs - fetching multiple model

i'm novice in backbonejs and i'm doing some project that includes fetching and displaying friends list. for this project i'm using parse.com as database. but i'm stocked at this point.
for example: i have following data's in user and friends models.
var user = [
{
id: 'x1',
firstname: 'Ashik',
lastname: 'shrestha',
phone: '12321321',
mobile: '123213',
email: 'xyz#gmail.com'
},
{
id: 'x2',
firstname: 'rokesh',
lastname: 'shrestha',
phone: '12321321',
mobile: '123213',
email: 'rokesh#gmail.com'
},
];
var friends = [
{
user_id: 'x1',
user_friend_id: 'x2'
},
{
user_id: 'x1',
user_friend_id: 'x4'
},
{
user_id: 'x1',
user_friend_id: 'x10'
},
{
user_id: 'x2',
user_friend_id: 'x25'
}
];
// collections
var userCollection = Backbone.collection.extend({
model: user
});
var friendListCollection = Backbone.collection.extend({
model: friends
});
var friends = new friendListCollection();
now what i want?
when i fetch friends collection object, i want to get friends list of user with their details.
example::
friends.fetch({
success: function(ob){
var ob =ob.toJSON();
// i want ob to be like
[
{
id: 'x2',
firstname: 'rokesh',
lastname: 'shrestha',
phone: '12321321',
mobile: '123213',
email: 'rokesh#gmail.com'
},
{
id: 'x4',
firstname: 'rokesh',
lastname: 'shrestha',
phone: '12321321',
mobile: '123213',
email: 'rokesh#gmail.com'
},
{
id: 'xx10',
firstname: 'rokesh',
lastname: 'shrestha',
phone: '12321321',
mobile: '123213',
email: 'rokesh#gmail.com'
},
]
}
});
should i create new collection to relate them or is there any other way to do this??
Thanks in advance!
To use the least of server requests to gain a better performance and less presure on server side, I would suggest you to add this logic on your server-side rather than here on client-side. e.g. When fetching with parameters like ?detail=true, the server then return simple information with detailed data, otherwise only return simple information.
If you have a good reason to seperate them into different Collections, you have to fetch those collections consequently.
Assuming you do not wish to change your data structure, you can use BackboneJS' model's idAttribute property, to retrieve a specific model from a collection by a specific key, usually an "id".
When you define your model, you should also define the idAttribute for the model, which will later allows your to access it from the collection, by the value of this field.
When a Backbone collection is synced, all models are parsed according to their defined structure, adding administrative functionality on top of their data.
Consider the following example:
var myModel = Backbone.Model.extend({
idAttribute: "id"
...
});
var myCollection = Backbone.Collection.extend({
model: myModel
...
});
Once myCollection holds one or more "myModel"(s) you can then simply use the following:
var myModelFromMyCollection = myCollection.get(id);
the idAttribute of the model can by any of the model's fields...
For your use case, lets assume both friendListCollection and userCollection are already available and have models in them, consider the following code to get the full details of each friend from it's user model like so:
friendListCollection.each(function(friendModel) {
var friendFullDetailsFromUsersCollection = userCollection.get(friendModel.id);
console.log(friendFullDetailsFromUsersCollection);
...
});

Resources