How to use find/findOne outside of a helper function - angularjs

I am trying to use a findOne statement to access a document from a collection, within a transform function.
this.helpers({
posts: function () {
return Posts.find(this.getReactively('filter'), {sort: {createdAt: -1}, transform: function (doc) {
var restaurant = Restaurants.findOne(doc.rest_id);
doc.restaurant = restaurant.name;
doc.neighborhood = restaurant.neighborhood;
return doc;
}});
}
});
The problem is that the call on findOne returns nothing (undefined). Similarly, using find.fetch() returns an empty Array.
After troubleshooting, I find that running find or findOne anywhere in my code except directly as a helper (i.e. return Posts.find() works fine) returns nothing. I've read that the client may not have finished subscribing to the data at this point, but nothing ever shows up on the client side.
Running the same Restaurants.find or findOne works fine on the Console, returning the expected documents.
Am I trying to do something not supported by angular-meteor? Are the find functions only supported within the context of a helper?

I think the part that you are missing here is that the transform function is being called by Mongo (i.e. in the Mongo call): this is not a callback function.
So, you need to fetch your documents, then findOne for each fetched document.
this.helpers({
posts: function () {
var my_posts = Posts.find(this.getReactively('filter'), {sort: {createdAt: -1}).fetch();
my_posts.forEach(function (doc) {
var restaurant = Restaurants.findOne(doc.rest_id);
doc.restaurant = restaurant.name;
doc.neighborhood = restaurant.neighborhood;
return doc;
}
});
});

Related

React: Method finishing before data loaded

I am trying to retrieve some data from Yahoo Finance using an XHTML Request, which works. However, I am trying to display the data retrieved on my app, but the method to retrieve the data is returning "undefined" before the data has been loaded.
async componentDidMount() {
var tempData = await this.fetchAsync();
console.log(tempData)
this.handleLoad(tempData)
}
handleLoad = (num) => {
this.setState(state => ({
price: num
}));
}
async fetchAsync () {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
const {params} = this.props.navigation.state;
var ticker = params.ticker;
var result;
var tempArray = [1];
var url = "https://yahoo-finance-low-latency.p.rapidapi.com/v8/finance/spark?symbols=" + ticker + "&range=2y&interval=1d"
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
result = JSON.parse(this.responseText);
tempArray = result[ticker]['close'];
testPrice = tempArray[tempArray.length-1]
console.log(testPrice)
var self = this;
return tempArray[tempArray.length-1]
}
});
xhr.open('get', url, true);
xhr.setRequestHeader("x-rapidapi-key", "my key");
xhr.setRequestHeader("x-rapidapi-host", "yahoo-finance-low-latency.p.rapidapi.com");
xhr.send();
}
I am using the componentDidMount() function to begin calling the methods to load the data, but when the app renders, the values are not displayed.
As you can see inside the fetchAsync() method, I return the value I need, but when I try and console.log the return from this method, I get undefined.
I have also tried moving this return to the end of the method, but when I use console.log here to ensure that tempArray has the data I need, it is empty.
I need to display tempArray[tempArray.length-1] on my screen, but the data is not loaded in time, and does not update even after it has loaded.
Your return tempArray[tempArray.length-1] inside the fetchAsync isn't actually returning from fetchAsync -- it's just returning from the callback function inside addEventListener. In fact, you don't actually have any code that is taking advantage of the async tag you have on that function.
One solution to this would be to call handleLoad directly from inside fetchAsync instead of return tempArray. (Of course, you'll want to make sure that you've bound this correctly to handleLoad).
Another solution would be to pass a callback function into fetchAsync that you could call instead of returning. Then, at your call site, it might look something like this:
this.fetchAsync((tempData) => {
console.log(tempData)
this.handleLoad(tempData)
});
Finally, a third solution would be to switch from XMLHTTPRequest to fetch, and then you could take advantage of async/await and actually make that fetchAsync method async (and be able to return a value from it).

How to call the $firebaseArray in the cloud function of firebase

So in my angular JS web app, I have a function that calls on a node in the firebase database called orderedPlayers and returns it as an array as follows:
$firebaseArray(orderedPlayers)
.$loaded(function(loadedPlayers) {
// function in here
});
When attempting to do something similar in the cloud function I am experiencing problems. Is there a way to return the the players node as an array?
I know i can access the database as follows:
admin.database().ref('orderedPlayers');
but the $firebaseArray doesnt work.
These docs can help: https://firebase.google.com/docs/database/admin/retrieve-data
snapshot.val() will return an object that can be referenced as a key-value array. In your case:
admin.database().ref('orderedPlayers').on("value", function(snapshot) {
var loadedPlayers = snapshot.val();
//access your players here
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
To the best of my knowledge cloudfunctions does not include firebaseArray. You can instead just make the players children into an array.
so:
let yourArray = [];
admin.database().ref('orderedPlayers').once('value').then(snap => {
snap.forEach(childSnap => {
yourArray.push(childSnap));
});
});
or you can use the children:
let yourArray = [];
admin.database().ref('orderedPlayers').on('child_added',snap => {
yourArray.push(snap);
});
*on('child_added') will always be called at least once so it removes the need to loop over the children.
If you want to query the database by a specific value you just add something like orderByChild('order') after the ref and before calling once or on

kinvey fetching and remove not working (AngularJS)

I have this problem with kinvey backend,
I'm trying to fetch data from my collection but it doesn't work for me. here is my code :
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
Can you help me please
If you let run the code you have posted then consider four things:
Make sure you have Kinvey implemented:
<script src="https://da189i1jfloii.cloudfront.net/js/kinvey-html5-sdk-3.10.2.min.js"></script>
Make sure you have initialized the Kinvey service before:
// Values shown in your Kinvey console
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
Make sure you are logged in with a user that has the rights to read your collection (should be fine using the All Users role (default)):
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
})
.catch(function(error) {
console.log (error);
});
Output the return result to see whats coming back. To make sure you do the query AFTER successful login, paste you query inside the .then function of login.
I'm not sure if your query is valid unter 3.x since a lot has changed and I'm not working with older Kinvey versions.
So that all together would look like this:
// Initialize Kinvey
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
// Login with already registered user
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
// Your query
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// Output of returning result
console.log (entity);
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
})
.catch(function(error) {
console.log (error);
});
There are now three return sets possible:
Nothing (as you say) -> Something missing/wrong in the code (compare yours with mine)
Empty array: Your query didn't find anything, adapt the search value(s)
One or more entries in the array -> All fine, what you were looking for!
Hope that helps!
When querying by _id there is a built in method: http://devcenter.kinvey.com/angular/guides/datastore#FetchingbyId
Try switching to var stream = dataStore.findById('entity-id');
Also check to make sure you don't have any preFetch or postFetch BL that is interfering with the query.

Angular firebase fetching single item has race conditions

I'm using angular and firebase together and I have a products array which i'm storing in my rootscope, though it takes time to load the items.
My issues is that when I go to this page for example directly:
http://localhost/product/greyish-sports-shoes
If I go to the home page, the products load after 2 seconds.. and then only if I click on the product link it takes me to it, and it'll work because products have already been loaded.
It goes to the shoeService which contains the products array, but the items are still not loaded, so it cannot find the product by its slug.
That's the code I use in my run method.
var ref = firebase.database().ref().child('products');
$rootScope.shopProds = $firebaseArray(ref);
My shoeService factory:
function shoeFactory($rootScope) {
this.service = {};
this.service.store = new Store($rootScope.shopProds);
this.service.cart = new Cart();
return this.service;
}
It is important to realize that the $firebaseArray service returns an array that is initially empty. The array is populated asynchronously after the data is returned from the server.
Use the promise returned by the $loaded method attached to the array:
function shoeFactory($rootScope) {
this.service = {};
this.service.storePromise = $rootScope.shopProds.$loaded()
.then ( (shopProds) => {
return new Store(shopProds);
});
this.service.cartPromise = this.service.storePromise
.then ( () => {
return new Cart();
}).catch( (error) => {
console.log("ERROR in shoeFactory");
throw error;
});
return this.service;
}
To avoid race conditions, the code needs to use promises to chain operations.

mapping the response to corresponding request

I am making $http request to multiple environment and processing after I get all the responses. I am using the code below:
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
var results = {};
for (var env in res) {
results[env] = res[env].data;
}
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json');
}
The above code works fine, but the results object looks like below:
{
0: {data:{}},
1: {data:{}},
2: {data:{}},
3: {data:{}}
}
I want the corresponding response for each key and the results should be like
{
env1: {data:{//data for env1}},
env2: {data:{//data for env2}},
env3: {data:{//data for env3}},
env4: {data:{//data for env4}},
}
How to map the corresponding response to the key? Please let me know how to get this as this is asynchronous request. Should I have something from the API to know which env the API is coming from?
I think the simplest way would be to push the result handling into the request function, that way you still have the 'env' value in scope.
var results = {};
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
// Do something with 'results' here.
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json')
.then(function(res) { results[env] = res.data; return env; });
}
Another option would be to replace my return env with return [env, res.data] and then you can go back to creating the results object as in your original code.
The important thing here is to remember you can handle the $http.get promises individually as well as using the promises from the call to then in $q.all.

Resources