Parse Promise and Parse Relation toghether - Javascript API - javascript

Ok guys! Could someone help me?
I have a parse DB as follow:
Person(id, name)
Product(id,serial)
Invoice(id,<Relation>products, personId)
I need to build a function that returns an array of Objects,
in each Object person.name, invoice.id,invoice.products
I'm not so good with english so I wish you understand what i mean.
so i use Parse.Promise to query the "person" and the "invoice"
function Obj(name, invoiceId, products) {
return {
name: name || '',
invoiceId: invoiceId || '',
products: products || []
};
}
function retreiveData(aName) {
var retval = [],
personQuery = new Parse.Query("Person");
personQuery.equalTo('name', aName).first().then(function(person) {
var invoiceQuery = new Parse.Query("Invoice");
return invoiceQuery.equalTo('personId', person.id).query().find();
}), then(function(invoices) {
//until here everythinks work fine
// now i've the invoices list and i have to look for related products
var promise = new Parse.Promise();
_.each(invoices, function(invoice) {
var obj = new Obj(aName, invoice.id),
promise = new Parse.Promise();
invoice.relation('products').query().find().then(function(products) {
obj.products = products;
// here i expect to have the obj fulfilled with all data
retval.push(obj);
promise.resolve();
});
return promise;
});
return promise;
});
}
var aName = 'Paul';
retreiveData(aName).then(function(retval) {
console.log('success');
/* here i have to have somethin like
retval=[{
name='paul',
invoiceId='12412412',
products=[{prod1},{prod2},{prod3}]
},{
name='paul',
invoiceId='67413412',
products=[{prod5},{prod10},{prod33}]
}]
*/
});
any idea?
i know the inner promise is wrong, but i don't understand how to fix
Thanks guyz!

Related

Infinite functions calls like 'string'.replace().replace()

I'm not really sure how to explain so I will start with the output.
I need to return this:
{
replies:
[
{ type: 'text', content: 'one' }
{ type: 'text', content: 'two' }
{ type: 'text', content: 'three' }
],
conversation: {
memory
}
}
And I wanted to return that through in-line statement.
So I would like to call something like:
reply.addText('one').addText('two').addText('three').addConversation(memory)
Note that addText can be called infinite times while addConversation can be called only one time. Also conversation is optional, in that case, if conversation is absent the conversation object should not appear in the output.
To create a custom structured object use a constructor, say Reply.
To call instance methods on the return value of method calls, return the instance object from the method.
Choices to prevent multiple additions of conversation objects include throwing an error (as below) or perhaps logging a warning and simply not add additional objects after a first call to addConversation.
Write the code to implement the requirements.
For example using vanilla javascript:
function Reply() {
this.replies = [];
}
Reply.prototype.addText = function( content) {
this.replies.push( {type: "text", content: content});
return this;
}
Reply.prototype.addConversation = function( value) {
if( this.conversation) {
//throw new Error("Only one conversation allowed");
}
this.conversation = {conversation: value};
return this;
};
Reply.prototype.conversation = null;
// demo
var reply = new Reply();
reply.addText( "one").addText("two").addConversation("memory?");
console.log( JSON.stringify( reply, undefined," "));
(The console.log uses JSON stringify to avoid listing inherited methods)
A possible implementation is to create a builder as follows:
function create() {
const replies = []; // store all replies in this array
let conversation; // store the memory here
let hasAddConversationBeenCalled = false; // a state to check if addConversation was ever called
this.addText = function(content) {
// add a new reply to the array
replies.push({
type: 'text',
content
});
return this; // return the builder
};
this.addConversation = function(memory) {
if (!hasAddConversationBeenCalled) { // check if this was called before
// if not set the memory
conversation = {
memory
};
hasAddConversationBeenCalled = true; // set that the memory has been set
}
return this; // return the builder
}
this.build = function() {
const reply = {
replies
};
if (conversation) { // only if converstation was set
reply.conversation = conversation; // add it to the final reply object
}
return reply; // finally return the built respnse
}
return this; // return the new builder
}
You can then use it as follows:
const builder = create();
const reply = builder.addText('one').addText('two').addText('three').addConversation({}).build();
Here is a link to a codepen to play around with.
If you specifically want to add assemble this via multiple function calls, then the builder pattern is your best bet, as vader said in their comment.
However, if the goal is to simply create shorthand for concisely building these objects, it can be done using a function that takes the list of text as an array.
const buildObject = (textArray, memory) => {
return Object.assign(
{},
{
replies: textArray.map(x => {
return {
type: 'text',
value: x
}
})
},
memory ? {conversation: memory} : null
)
}
var memory = { };
//with memory
console.log(buildObject(['one', 'two', 'three'], memory ))
//without memory
console.log(buildObject(['one', 'two', 'three']));
Fiddle example: http://jsfiddle.net/ucxkd4g3/

Multi level Promise in nodejs

I have a problem with promise
I want to get all Category and sub Category ( Multi level Category) using promise. But i can't get multi level promise. I can get first Promise use Promise.all(Array) but can't get child promise.
getChild: function(_cats){
var arrCat=[];
var that = this;
for (var i = 0, len = _cats.length; i < len; i++) {
var t = new Promise(function(resolve,reject){
var a = [];
var _c = _cats[i];
_cats[i].getChildren(function(err, _childs){
a.push({
root: _c,
child: that.getChild(_childs)
});
resolve(a);
})
})
arrCat.push (t);
}
return Promise.all(arrCat);
and other function to call and respon api:
this.getChild(_cats).then(_r => {
return res.ok(_r);
})
and the respone
[{
root: {value} // it's ok
child: promise(pending) //it's problem
}]
Please help me! thank you!
First extract promisified version of cat.getChildren to make code clear. Then map over all categories and for each category return a Promise that resolves only after every nested child is loaded by recursively calling getChild. Something like this should do the trick
function getChildren(cat) {
new Promise(function(resolve) {
cat.getChildren(function(_, children) {
resolve(children)
})
})
}
getChild: function getChild(_cats) {
return Promise.all(
_cats.map(function(cat) {
return getChildren(cat)
.then(getChild) // load each child
.then(function(children) {
return {
root: cat,
children: children
}
})
})
)
}
This code work perfect. Thanks to Yury
function getChildren(cat) {
new Promise(function(resolve) {
cat.getChildren(function(_, children) {
resolve(children)
})
})
}
getChild: function getChild(_cats) {
return Promise.all(
_cats.map(function(cat) {
return getChildren(cat)
.then(getChild) // load each child
.then(function(children) {
return {
root: cat,
children: children
}
})
})
)
}

Javascript function to return Elasticsearch results

I'm trying to write a JavaScript function that returns results of an Elasticsearch v5 query. I can't figure out where and how to include 'return' in this code. With the following, segmentSearch(id) returns a Promise object,{_45: 0, _81: 0, _65: null, _54: null}.
_65 holds an array of the correct hits, but I can't figure out how to parse it. The console.log(hits) produces that same array, but how can I return it from the function?
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'localhost:9200',
log: 'trace'
});
segmentSearch = function(id){
var searchParams = {
index: 'myIndex',
type: 'segment',
body: {
query: {
nested : {
path : "properties",
query : {
match : {"properties.source" : id }
},
inner_hits : {}
}
}
}
}
return client.search(searchParams).then(function (resp) {
var hits = resp.hits.hits;
console.log('hits: ',hits)
return hits;
}, function (err) {
console.trace(err.message);
});
}
I would instanitate a new array outside of your client.search function in global scope and array.push your 'hits' Then access your newly filled array.
let newArr = [];
client.search(searchParams).then(function (resp) {
for(let i = 0; i < resp.hits.hits.length; i++){
newArr.push(resp.hits.hits[i]);
}
console.log('hits: ',newArr)
return newArr;
}, function (err) {
console.trace(err.message);
});
First of all, elasticsearch js client is working with Promise ( I think using callback is also possible).
Using Promise is a good way to handle asynchronous computation.
In your question, you have already done something with a promise:
var search = function(id)
{
var searchParams = { /** What your search is **/}
return client.search(searchParams)
}
This call is returning a Promise.
If we consider handleResponse as the function in your then
var handleResponse = function(resp)
{
var hits = resp.hits.hits;
console.log('hits: ',hits)
return hits; //You could send back result here if using node
}
In your code, handleResponse is called once the promise is fullfield. And in that code you are processing data. Don't forget you are in asynchronious, you need to keep working with promise to handle hits.
By the way, in your question, what you have done by using "then" is chaining Promise. It is normal to have Promise.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
Promise.prototype.then is returning a Promise.
var segmentSearch = function ( id )
{
return search
.then( handleResponse //here you got your hit )
.then( function ( hits )
{
console.log(hits) //and here you have done something with hits from search.
})
}
I neglected to post my fix, sorry about that. The sequence is to create searchParams, perform client.search(searchParams) which returns a Promise of hits, then process those hits:
segmentSearch = function(obj){
// retrieve all segments associated with a place,
// populate results <div>
let html = ''
var plKeys = Object.keys(obj)
var relevantProjects = []
for(let i = 0; i < plKeys.length; i++){
relevantProjects.push(obj[plKeys[i]][0])
var searchParams = {
index: 'myIndex',
type: 'segment',
body: {
query: {
nested : {
path : "properties",
query : {
match : {"properties.source" : id }
},
inner_hits : {}
}
}
}
}
client.search(searchParams).then(function (resp) {
return Promise.all(resp.hits.hits)
}).then(function(hitsArray){
...write html to a <div> using hits results
}
}

Javascript Promises: Iterate over all object keys arrays and then resolve

I have this JS object:
let setOfWords = {
"nouns": [
"work",
"construction",
"industry"
],
"verbs": [
"work"
],
}
I'm using the google translate API which calls a REST resource, so I need to wait for the response of each translation and then resolve the same object structure but with the translated words.
function translateByCategory(){
let translatedObj = {};
return new Promise(function(resolve, reject){
Object.keys(obj).forEach(function(category){
if (translatedObj[category] == undefined) {
translatedObj[category] = [];
}
setOfWords.forEach(function(word){
google.translate(word, 'es', 'en').then(function(translation){
translatedObj[category].push(translation.translatedText);
});
});
// return the translatedObj until all of the categories are translated
resolve(translatedObj);
});
});
}
You can use Promise.all() to wait for all promise fulfillments (or first rejection):
var translateRequests = [];
Object.keys(setOfWords).forEach(function(category){
setOfWords[category].forEach(function(word){
translateRequests.push(google.translate(word, 'es', 'en'));
});
});
});
Promise.all(translateRequests).then(function(translateResults){
//do something with all the results
});
See the docs: Promise.all()
Individual promises need to be aggregated with Promise.all() and fundamentally, that's what's missing.
But you can do better by reducing the number of calls to the Google service.
The Google translate API allows multiple text strings to be translated in one hit by passing an array of words instead of one word per call, giving you a performance advantage though probably not price advantage - google currently charges for its translation service "per character", not "per call".
I can't find any documentation for google.translate() but, with a few assumptions, you may be able to write :
function translateByCategory(obj, sourceCode, targetCode) {
let translatedObj = {};
var promises = Object.keys(obj).map(function(key) {
return google.translate(obj[key], sourceCode, targetCode).then(function(translations) {
translatedObj[key] = translations.map(function(t) {
return t.translatedText || '-';
});
}, function(error) {
translatedObj[key] = [];
});
});
return Promise.all(promises).then(function() {
return translatedObj;
});
}
If that doesn't work, then this documentation explains how to call google's RESTful translation service directly.
You should be able to write :
function translateTexts(baseParams, arrayOfStrings) {
let queryString = baseParams.concat(arrayOfStrings.map(function(str) {
return 'q=' + encodeURIComponent(str);
})).join('&');
return http.ajax({ // some arbitrary HTTP lib that GETs by default.
url: 'https://translation.googleapis.com/language/translate/v2?' + queryString,
}).then(function(response) {
return response.data.translations.map(function(t) {
return t.translatedText || '-';
});
}, function(error) {
translatedObj[key] = []; // on error, default to empty array
});
}
function translateByCategory(obj, sourceCode, targetCode) {
let baseParams = [
'key=' + MY_API_KEY, // from some outer scope
'source=' + sourceCode, // eg 'en'
'target=' + targetCode // eg 'es'
];
let translatedObj = {};
let promises = Object.keys(obj).map(function(key) {
return translateTexts(baseParams, obj[key]).then(function(translations) {
translatedObj[key] = translations;
}, function(error) {
translatedObj[key] = []; // on error, default to empty array
});
});
return Promise.all(promises).then(function() {
return translatedObj;
});
}
In either case, call as follows :
let setOfWords = {
"nouns": [
"work",
"construction",
"industry"
],
"verbs": [
"work"
],
};
translateByCategory(setOfWords, 'en', 'es').then(function(setOfTranslatedWords) {
console.log(setOfTranslatedWords);
});
The method suggested by #hackerrdave can be modified to make it more compatible with async await feature of JavaScript, do this like the following:
function translateByCategory(){
return new Promise(function(resolve, reject){
var translateRequests = [];
Object.keys(setOfWords).forEach(function(category){
setOfWords[category].forEach(function(word){
translateRequests.push(google.translate(word, 'es', 'en'));
});
});
Promise.all(translateRequests).resolve(resolve(translateRequests));
});
}
So now you can do something like:
let translatedObj = await translateByCategory();
And you will get what you want in "translatedObj".

How to resolve my promise calls in my case

I was trying to reduce my promise objects in my service. I have something like
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var service = {};
var firstEmp;
var deferred = $q.defer();
Employees.query({
Id: 123
}, function(objects) {
firstEmp = objects[0];
deferred.resolve(objects);
})
service.getFirstEmployee = function() {
var deferredtwo = $q.defer();
// return deferredtwo.promise;
//How to solve the double promise defer in my case
//First promise is wait for the whole employees
//this one is to return first employee
deferred.promise.then(function(){
deferredtwo.resolve(firstEmp);
})
return deferredtwo.promise;
}
return service;
]);
Controller
testService.getFirstEmployee.then(function(firstEmployee){
console.log(firstEmployee) <---show first employee
})
I am not sure how to resolve the double promise objects. Can anyone help me? Thanks a lot!
If your ultimate objective is just to get the first employee, then you don't need all this "double promise" stuff at all. Just resolve one promise with the first employee:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var pFirstEmployee = $q(function (resolve) {
Employees.query({ Id: 123 }, function(objects) {
resolve(objects[0]);
});
});
return {
getFirstEmployee: function() {
return pFirstEmployee;
}
};
}
]);
If you want two methods - one that returns a promise for all employees returned from the query, and another that returns just the first one from that set, just create a promise for all the employees and chain off of that:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var pAllEmployees = $q(function (resolve) {
Employees.query({ Id: 123 }, resolve);
}),
pFirstEmployee = pAllEmployees.then(function (employees) {
return employees[0];
});
return {
getAllEmployees: function() {
return pAllEmployees;
},
getFirstEmployee: function() {
return pFirstEmployee;
}
};
}
]);
After the clarification I guess this is what you want:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var service = {};
var deferred = $q.defer();
Employees.query({Id: 123}, function(objects) {
firstEmp = objects[0];
deferred.resolve(objects);
});
service.getFirstEmployee = function() {
return deferred.promise.then(function(employees){
return employees[0];
});
}
return service;
]);

Categories

Resources