Add Relational Query Data to main JSON result - javascript

in my Angular app I'm trying to display a set of results that come from three Classes. Data is stored on Parse.com.
I can do just fine with the Pointer relation type for one-to-one (associated scores are being returned).
Problem starts when I try to include data from the Location class into my final returned JSON.
Hopefully this is just a basic notation thing I'm missing.
Thanks a lot!
Doctors
String: firstname
Pointer: score
Relation: location
Scores
Number: scoreOne
Number: scoreTwo
Locations
String: name
String: address
.controller('BrowseCtrl', function($scope) {
// Get "Doctors" and associated "Scores"
// via Pointer in Doctors Class named "score"
var query = new Parse.Query("Doctors");
query.include("score");
query.find()
.then(function(result){
var doctorsArray = new Array();
for(i in result){
var obj = result[i];
var doctorIds = obj.id;
var docFirstname = obj.get("firstname");
var mainScore = obj.get("score").get("mainScore");
doctorsArray.push({
Scores:{
DocMainScore: mainScore
},
firstname: docFirstname,
});
}
// Get Locations.
// -can be more than one per Doctor
// Class Doctors has a Relation column "location" pointing to Locations
var locationsArray = new Array();
var locationRelation = obj.relation('location');
var locationQuery = locationRelation.query();
locationQuery.find({
success: function(locations) {
for(j in locations){
var locObj = locations[j];
var locName = locObj.get("name");
console.log(locName);
}
}
})
// send data to the view
$scope.myData = doctorsArray;
console.log(doctorsArray);
});
})
What I am trying to do is get the data from Locations into the doctorsArray.

First of all, you are using obj outside the for where it's assigned. This way it'll only get location for the last doc, I'm pretty sure it's not what you wanted.
What you want must be something like this:
// inside your Doctors query result
Parse.Promise.when(
// get locations for all doctors
result.map(function(doc) {
return doc.relation('location').query().find();
})
).then(function() {
var docsLocations = arguments;
// then map each doctor
$scope.myData = result.map(function(doc, i) {
// and return an object with all properties you want
return {
Scores: {
DocMainScore: doc.get('score').get('mainScore')
},
firstname: doc.get('firstname'),
locations: docsLocations[i]
};
});
});

Related

Node js - How to return array multidimensional

I need to create an array with this structure:
[
{
position: 2,
family: 9404,
part: [ 'article1', 'article2', 'article3' ]
},
{
position: 3,
family: 9405,
part: [ 'article4', 'article5', 'article6' ]
}
]
So i have a form where i select the parts that i want and send the families to get url.In the getter function i do a for to get the articles of each family and i want to query a select of articles and a select of positions. After that i try to push each array to a main array but i can't, show me undefined. How can i do this kind of operations?
I'm new with node and express and this is the first time that i have to do that.
My code:
getFamilies(req, res)
{
console.log(req.params.data);
var parsedData = JSON.parse(req.params.data);
var compounds = parsedData[0].compounds;
var supplier = parsedData[0].supplier;
var families = parsedData[0].families;
console.log(parsedData[0].compounds.length);
var position = [];
var data = [];
var parts = [];
for (var i = 0; i < compounds.length; i++)
{
parts.push(request.query("SELECT st.ref, st.design FROM st WHERE familia ='"+families[i]+"'"));
position.push(request.query("SELECT u_order FROM u_part WHERE u_familia='"+families[i]+"'"));
}
return Promise.all(parts, position, families).then(function(listOfResults)
{
//add parts, position and families to data[]
var data = [];
//console.log(data);
console.log(listOfResults);
console.log("done");
//return listOfResults;
res.render('view2', {teste: data});
}).catch(function(err)
{
// ... query error checks
console.log(err);
});
}
In promise just print the first parameter "parts" and if i put the [parts, position, families] give me promise pending.
And how can i put the data in the structure that i show above.
parseData:
[
{
"compounds": ["8"],
"supplier": ["sup"],
"families": ["9305"]
}
]
Please teach me how can i do this kind of operations.
Thank you
Not sure why you're passing families to Promise.all families seems to just be an array of data from taken from the query
Promise.all takes an array of promises in input, and you're passing an array of arrays of promises and of data...
you should never build SQL queries like this. This is a big flaw for SQL injection (but that's another question)
So do:
Promise.all([...parts, ...position]) or if you're not using ES6 syntax Promise.all(parts.concat(position))
and fix your SQL!
====
Final code could look like:
getFamilies = (req, res) => {
var families = JSON.parse(req.params.data)[0].families;
var positions = [];
var data = [];
var parts = [];
families.forEach(family => {
// see http://stackoverflow.com/a/7760578/2054629 for mysql_real_escape_string
parts.push(request.query("SELECT st.ref, st.design FROM st WHERE familia ='"+mysql_real_escape_string(family)+"'"));
positions.push(request.query("SELECT u_order FROM u_part WHERE u_familia='"+mysql_real_escape_string(family)+"'"));
});
return Promise.all([Promise.all(parts), Promise.all(positions)]).then(listOfResults => {
var [partResult, positionResult] = listOfResults;
var data = families.map((family, i) => {
var pos = positionResult[i];
var parts = partResult[i];
return {family: family, position: pos, parts: parts};
});
res.render('view2', {teste: data});
}).catch(err => {
// ... query error checks
console.log(err);
});
};
You incorrectly use Promise.all, it takes array of promises
return Promise.all([Promise.all(parts), Promise.all(position)]).then(function(listOfResults){
var partResult = listOfResults[0];
var positionResult = listOfResults[1];
var data = [];
for (var i=0; i<families.length; i++) {
var family = families[i];
var pos = positionResult[i];
var parts = partResult; // logic to extract parts for current family
data.push({family: family, position: pos, parts: parts})
}
console.log(data);
})
Promise.all() takes an array of promises, it looks like you are passing multiple arrays.

Understanding promises a little more

I'm struggling to make this works. i'm dealing with sequelize promisses and i want to return the queried elements to the view, but instead its returning null. I know its because promises are async requests and it does not return a result immediatly after you call it, ok, but how to return the values, put it into an array and than return the array?
this is the code i have so far.
router.post('/register', function(req, res, next) {
var sales = req.body.sales;
var person = req.body.personID;
var promisses = [];
var delivery = req.body.delivery;
for(var i =0;i<sales.length;i++){
var product_id = sales[i].product_id;
var amount = sales[i].amount;
var price = sales[i].produto_price;
var salePromisse = Sale.create({
'product_id': product_id,
'person_id': person,
'amount': amount,
'price': price,
'total': amount*price
});
//i couldnt find a word which describes what movimentacao means...lets keep it.
var movimentacao = Movimentacao.create({
"tipo": 0,
"id_product": product_id,
"id_provider": "",
"data": new Date(),
"price": amount*price
});
promisses.push(salePromisse);
promisses.push(movimentacPromisse);
}
Promise.all(promisses).then(function (promissesArray){
var name = "";
var suc = 0;
var total = 0;
var salesResult = [];
var salesObject = {};
if(!delivery){
res.send({msg: "aaaaa"});
}else{
promissesArray.forEach(function(pro){
if(pro!==null && pro !== undefined){
if(pro['$modelOptions'].tableName === undefined){
Product.findById(pro.product_id).then(function (product){
salesObject.product = product.name;
salesObject.price= pro.price;
salesObject.amount = pro.amount;
salesObject.total = pro.total;
total += salesObject.total;
salesResult.push(salesObject);
salesObject = {};
return Person.findById(per);
}).then(function (person) {
name = person.name;
});;
}
}
});
//here is where i would like to return to the view salesResult and name.
//res.render("folder/view", {sales: salesResult, person: name});
console.log(salesResult);
}
});
});
Well, the promisses array has the CREATE instance for each of my models, and i'm creating a few types of it.
I want to insert on the database, check if the promise resolved is dealing with an specific table (the field modelOptions is undefined on it, i already debugged), query all the other results because on the promisses array i have just the id, and than put into the array to be able to return to the view, but on the console.log on the last line, it returns null. How can i improve the code to be able to do all i want and than return to the view?
Dont worry, all the model related variables are beeing declared above.
Thanks.

Angular Factory and Service work but not as expected

My app is looking up google place details and displaying some of the information. I have a list of place id's in a json file broken down by type of establishment. A factory accesses and makes available the ids to the controller. I also have a service that loops through all the id's, looking up the details and adding them to an object that is made available to the controller.
I can get it to work in the sense that I can access the json data, look up the details, and return the object. However, no matter how I do it, if I try and return multiple objects, one for each type of business, I get all the businesses together or an error (more on that in a minute).
I have structured this a number of ways but I will show the code for 2 ways that I have tried. I'm new to Angular so I may have this completely wrong and not even using services and factories correctly so please go easy on me.
locations.json
{
"restaurants": {
"Michaels": "ChIJwaTJAL4n5IgRgyJupbpQhjM",
"Collage": "ChIJw5HgNzAm5IgRqbkEqKXIpC4",
"Scarlet": "ChIJT9ImkZUn5IgREb1hYwKA1Nc",
"Maya": "ChIJofgqBJYn5IgRVa-HQvp6KDk",
"Ice": "ChIJnXpQpewn5IgR7k9yxWXUu1M",
"Sangrias": "ChIJITcc_ZUn5IgR90iEna6FRGM",
"Columbia": "ChIJ8xR18JUn5IgRfwJJByM-quU",
"Harrys": "ChIJ8aLBaJYn5IgR60p2CS_RHIw"
},
"bars":
{
"Scarlet": "ChIJT9ImkZUn5IgREb1hYwKA1Nc",
"Lion": "ChIJqVCL_b0n5IgRpVR5CFZWi4o",
"Tradewinds": "ChIJpwF4ZJYn5IgRTDzwBWvlSIE",
"Ice": "ChIJnXpQpewn5IgR7k9yxWXUu1M",
"Stogies": "ChIJlwkiApYn5IgR6XVFMyqLAS4",
"Rondeazvous": "ChIJkz3V7pUn5IgRQhui26imF1k",
"Meehan": "ChIJK8NZGZYn5IgRA91RrGETwrQ",
"Sangrias": "ChIJITcc_ZUn5IgR90iEna6FRGM",
"NoName": "ChIJA-VeCb4n5IgRmbuF8wdOGaA",
"StGeorge": "ChIJ4yo36JUn5IgRXgiRD7KMDe0"
}
}
Method 1
locations.js
angular.module('app.locations', [])
.factory('restsFact', function($http){
var restaurants = [];
return {
getRests: function(){
return $http.get('locations.json').then(function(response){
restaurants = response.data.restaurants;
return restaurants;
});
}
};
})
.factory('barsFact', function($http){
var bars = [];
return {
getBars: function() {
return $http.get('locations.json').then(function(response){
bars = response.data.bars;
return bars;
});
}
};
})
.service('locationsService', function (ngGPlacesAPI) {
var x, id, details, push, placeDetails = [];
// Takes list of specific type of locations as argument and looks up Place details for each location
this.details = function(type) {
for (x in type) {
if (type.hasOwnProperty(x)) {
id = type[x];
ngGPlacesAPI.placeDetails({placeId: id}).then(push);
}
}
return placeDetails;
};
push = function (data) {
details = data;
placeDetails.push(details);
};
});
Controllers
.controller('RestCtrl', function($scope, locationsService, restsFact) {
// Location Details Object
restsFact.getRests().then(function(locs){
$scope.restaurants= locationsService.details(locs);
});
})
//
// Bar Controller
//
.controller('BarsCtrl', function($scope, locationsService, barsFact){
// Locations Details Object
barsFact.getBars().then(function(locs){
$scope.bars = locationsService.details(locs);
});
})
Method 2
With this method I can load one page but if I move to the next I get an error: [$rootScope:inprog] $digest already in progress. I read up on the error and get the idea of why I get it but just not sure how to go about fixing it.
locations.js
angular.module('app.locations', [])
.factory('locationsFact', function($http){
var locations = [];
return {
getlocations: function(){
return $http.get('locations.json').then(function(response){
locations = response;
return locations;
});
}
}
})
.service('locationsService', function (ngGPlacesAPI) {
var x, id, details, push, placeDetails = [];
// Takes list of specific type of locations as argument and looks up Place details for each location
this.details = function(type) {
for (x in type) {
if (type.hasOwnProperty(x)) {
id = type[x];
ngGPlacesAPI.placeDetails({placeId: id}).then(push);
}
}
return placeDetails;
};
push = function (data) {
details = data;
placeDetails.push(details);
};
});
Controller
.controller('locationsCtrl', function($scope, locationsService, locationsFact){
// Locations Details Object
locationsFact.getlocations().then(function(locs){
$scope.restaurants = locationsService.details(locs.data.restaurants);
$scope.bars = locationsService.details(locs.data.bars);
});
})
So I read a lot over the last week and learned a lot as well. I completely rewrote that mess up above into something resembling decent code, there were a lot of problems with it originally. I got everything working anyway. Here is how it looks now.
Factory
angular.module('app.factories', [])
.factory('data', function($http){
// Get JSON With Place ID's and create array of
// place id objects for each category
var places = {};
places.ids = function(){
return $http.get('locations.json')
.success(function(data){
places.rests = data.restaurants;
places.bars = data.bars;
places.lodg = data.lodging;
places.att = data.attractions;
});
};
return places;
})
.factory('details', function(ngGPlacesAPI, $q){
var details = {};
// Split ID Array into array of arrays <= 10.
// Google won't return more than 10 details request at one time.
details.process = function(type) {
var idSets = {},
size = 10,
i, j, k;
for (i=0, j=type.length, k=0; i<j; i+=size){
idSets[k] = type.slice(i, i+size);
k++;
}
return idSets;
};
// Lookup Details by Place ID
// Loop through ID array and return array of details objects
details.getDetails = function(idSet, pageNum) {
var page = idSet[pageNum],
promises = [];
for(var i=0; i<page.length; i++) {
promises.push(ngGPlacesAPI.placeDetails({placeId: page[i][i]}));
}
return $q.all(promises);
};
// Return Details Object
return details;
});
Controller
//
// Restaurants Controller
//
.controller('restaurantsCtrl', function(details, data, $scope) {
var vm = this;
// Get JSON file with placeIds and set some variables
data.ids().then(function() {
var page = details.process(data.rests),
pageNum = 0,
numPages = page.length;
vm.moreData = true;
// Loads more place details on scroll down
vm.loadMore = function() {
if (pageNum <= numPages - 1) {
pageNum++;
details.getDetails(page, pageNum).then(function(response) {
vm.rests.push(response);
vm.$broadcast('scroll.infiniteScrollComplete');
});
}else{vm.moreData=false}
};
// Load first page of place details
details.getDetails(page, pageNum).then(function(response){
vm.rests = response;
console.log(vm.rests);
});
// Watches for when to load more details
$scope.$on('$stateChangeSuccess', function(){
vm.loadMore();
});
});
})

How to create an array and push for object properties?

I have a situation where I have values from the backend dataItem. Now I want to push these values to an array and set for object properties, so next step would be map object properties to he form fields. With below code I got the values and assign it to object selectedOwners and its working good, but problem is everytime user addProcessOwner is creating new object for every user and when $scope.processDTO.prcsOwner = selectedOwners.fullName; do this its only assigning last value to the form field.
Once user select multiple owners how can I display all owners into form field?
main.html
<input type="text" class="form-control customReadOnly"
id="prcsOwner" required ng-model="processDTO.prcsOwner"
ng-click="openPrcsOwner()" ng-disabled="PROCESS_EDIT"/>
ctrl.js
var selectedOwners = {};
$scope.selectedOwnerGrid = rcsaAssessmentService.selectedProcessOwners();
$scope.addProcessOwner = function(dataItem) {
selectedOwners = {
fullName: dataItem.fullName,
workerKey: dataItem.workerKey
}
console.log('WORKER DATA', selectedOwners);
}
$scope.selectedProcessOwner = function() {
$scope.prcsOwnerModal.close();
$scope.processDTO.processOwnerWorkerKey = selectedOwners.workerKey;
$scope.processDTO.prcsOwner = selectedOwners.fullName;
console.log('FORM DATA', $scope.processDTO.processOwnerWorkerKey, $scope.processDTO.prcsOwner);
};
I think that what you trying to do is this:
var selectedOwners = [];
...
var selectedOwner = {
fullName: dataItem.fullName,
workerKey: dataItem.workerKey
}
selectedOwners.push(selectedOwner);

pass variable from Backbone.js router initialize function to the forEach statement of another router function

Please see updated code below...
I am attempting to filter one backbone collection by the attributes of another collection using a forEach statement. How can I write this in order to maintain the reference to the variable "this.neighborhoodsCollection" within the forEach statement. This may be less of a backbone question and more of a javascript question. I guess, in other words, how do I pass in the variable "this.neighborhoodsCollection" into my forEach statement. Here are the steps I am trying to take:
I pass the results of fetching my StoryCollection and NeighborhoodsCollection to the Router:
$(document).ready(function() {
var neighborhoodsCollection = new NeighborhoodsCollection();
neighborhoodsCollection.fetch({
success: function(){
var storyCollection = new StoryCollection();
storyCollection.fetch({
success: function () {
var app = new AppRouter(neighborhoodsCollection, storyCollection);
Backbone.history.start();
}
});
}
});
});
Then I set the passed in arguments as local variables...
initialize: function(neighborhoodsCollection, storyCollection){
this.neighborhoodsCollection = neighborhoodsCollection;
this.storyCollection = storyCollection;
}
In another function within the router, I check the array of neighborhoods in the current storyCollection against every neighborhood attribute in the Neighborhoods collection, and if there is a match, I add the Neighborhoods collection object to my Leaflet map.
load_story:function (id) {
//get Stories model object by id
this.story = this.storyCollection.get(id);
var storyNeighborhoods = this.story.attributes.neighborhoods;
storyNeighborhoods.forEach(function(neighborhood){
var hood = this.neighborhoodsCollection.attributes;
var nabe = [];
var nabeGeo = [];
for(var i = 0; i < _.size(hood); i++){
nabe.push(this.neighborhoodsCollection.attributes[i].properties.neighborhood);
nabeGeo.push(this.neighborhoodsCollection.attributes[i]);
var filterNabe = $.inArray(neighborhood, nabe);
if(filterNabe > -1){
L.geoJson(nabeGeo).addTo(map);
}else{
console.log('not found')
}
}
});
}
UPDATE
#Quince's answer set me on the right track, using pluck and intersection undescore helpers. Now I have an array containing every matching neighborhood string. Then I try to use that string to perform a get on the collection. Here is the data structure of my collection:
Object { cid: "c1", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object, _pending: false }
And here is the structure of the lone object in my collection:
[{ "id": "Greenpoint", "type": "Feature", "properties": { "neighborhood": "Greenpoint", "boroughCode": "3", "borough": "Brooklyn" ... }]
However I cannot successfully perform a get(id) on this collection. Maybe it has something to do with needing to create a model from each object in the collection, or something like that?
For reference, here is the relevant code based on #Quince example:
var neighborhoodsCollection = this.neighborhoodsCollection;
var neighborhoodsCollectionObjects = this.neighborhoodsCollection.attributes;
var neighborhoodsCollectionProperties = _.pluck(neighborhoodsCollectionObjects, 'properties');
var neighborhoodsCollectionArray = _.pluck(neighborhoodsCollectionProperties, 'neighborhood');
var storyCollectionNeighborhoods = this.story.attributes.neighborhoods;
var neighborhoodIntersection = _.intersection(storyCollectionNeighborhoods, neighborhoodsCollectionArray);
The value of neighborhoodIntersection is an array that includes the single string "Greenpoint"
neighborhoodIntersection.forEach(function(neighborhood){
neighborhoodsCollection.get(neighborhood);
});
I hope i understood this right, you want to look through each story and if it has a neighborhood that matches one of the neighborhoods form the main neighborhood collection then you want to grab a reference to it?
The way would go about this is to use underscores intersection function when comparing the id's in the story's neighborhood collection to the id's in the main neighborhood collection. Then use this list to grab the actual references from the main neighborhood collection. Below is an example of what i mean (or the code pen so you can see in the console that the references are obtained)
//setup of models and collections
var NeighbourHoodModel = Backbone.Model.extend({
defaults:{
name: null
}
});
var StoryModel = Backbone.Model.extend({
defaults:{
neighbourhoods:null
}
});
var NeighborhoodsCollection = Backbone.Collection.extend({
model: NeighbourHoodModel
});
var StoryCollection = Backbone.Collection.extend({
model: StoryModel
})
var neighbourHoods = new NeighborhoodsCollection([
{ id:1,name: "neighbourhood-1"},
{ id:2,name: "neighbourhood-2"},
{ id:3,name: "neighbourhood-3"},
{ id:4,name: "neighbourhood-4"}
]);
var stories = new StoryCollection([
{ id:1, neighbourhoods: new NeighborhoodsCollection([
{ id:1,name: "neighbourhood-1"},
{ id:2,name: "neighbourhood-2"}
]),
},
{ id:2, neighbourhoods: new NeighborhoodsCollection([
{ id:1,name: "neighbourhood-1"},
{ id:2,name: "neighbourhood-2"}
]),
}
]);
(function(neighbourHoods,stories){
var _matchedNeighbourhoodIds = [];
//grab an array (usign pluck) of all the nighboorhood ids
//do this here so don;t have to do it on every loop
var neighbourhoodIds = neighbourHoods.pluck("id");
stories.forEach(function(story){
//for each story grab an array (using pluck) of all the stories neighborhoods
//perform an intersection of the two arrays (returning an array of id's that appear in both lists)
//slice that array
//for each element add it to the _matchNeighbourhoods in at a sorted index (this is so that we don't end with duplicates in the array)
_.intersection(story.get("neighbourhoods").pluck("id"),neighbourhoodIds).slice(0).forEach(function(neighbourhoodId){
_matchedNeighbourhoodIds[_.sortedIndex(_matchedNeighbourhoodIds,neighbourhoodId)] = neighbourhoodId;
});
});
_matchedNeighbourhoodIds.forEach(function(matchedNeighbourHoodId){
console.log(neighbourHoods.get(matchedNeighbourHoodId));
});
})(neighbourHoods,stories);
One problem i have just seen after making this is with _.sortedIndex, although the array contains only unique id's for the matchedNeighbourhoods, it is still taking the time to over-right the the values when already matched neighborhoods are added.

Categories

Resources