Fetch Data from WatermelonDB in React - javascript

I am using WatermelonDB as a local database of my app.
I have a method getPlaces() inside a class AccessDB:
static async getPlaces() {
const postsCollection = database.collections.get('places');
const allPosts = await postsCollection.query().fetch();
return allPosts;
}
Calling getPlaces() using AccessDB.getPlaces() with async and await works. How can I fetch the results matching the query?

The variable allPosts is an array with all places in your case. So to access the properties of the places, you would do in a different class:
import AccessDB from './AccessDB';
and then somewhere for example
(async () => {
try {
const places = await AccessDB.getPlaces();
var buffer = '';
for (place in places) {
buffer += places[place].name + '\n'
}
console.log(buffer)
} catch(e) {console.log(e)}
})()
You have to be carefully when debugging with console.log, as
1) console.log skips outputs if executed fast one after the other, e.g. if you console.log the places[place].name every time in the for-loop above and
2) if you console.log(places) you see the same as if you console.log(database) which is very confusing. You would expect to see [Object object],[Object object]..., which you see when you use alert(places).

Maybe I am not understanding fully. But did you try to put query inside your query method
const allPosts = await postsCollection.query(Q.where('is_verified', true)).fetch();
Also do not forget that getPlaces is async and your need async\await to get return data.

Related

How to retrieve object from JSON in nodejs?

Having this code:
const fs = require('fs')
const file = 'books.json';
class Book{
constructor(code) {
this._code = code;
}
get code() {
return this._code;
}
set code(value) {
this._code = value;
}
}
async function writeBooks(){
const data = JSON.stringify([new Book('c1'), new Book('c2')]);
await fs.promises.writeFile(file, data, 'utf8');
}
async function getBook(code){
try{
const data = await fs.promises.readFile(file);
const array = JSON.parse(data);
return array.find(b => b.code === code);
} catch (err){
console.log(err)
}
}
writeBooks();
getBook('c1').then(b => console.log(b));
I am getting undefined (instead of the expecting book object).
How to get the object (the above problem)
If async function always returns promise, how can I then return object for the client, instead of him having to call then() from the getBook(code)?
do I need to await for the fs.promises.writeFile()? as I am doing in writeBooks()? As fas as I understand the async/await now, is that the return value from await function is the data or error. But since the writeFile() does not returns anything, or error at most (as opposed to readFile()) why would I want to await for no data?
Actually the root of problem is not about async/awaits or promises. The problem is trying to write an array to a json file. If you write your json data like the code snippet below (as a key-value pair), your problem is solved.
{"1": [new Book('c1').code, new Book('c2').code]} //as a key-value pair
const fs = require('fs')
const file = 'books.json';
class Book{
constructor(code) {
this._code = code;
}
get code() {
return this._code;
}
set code(value) {
this._code = value;
}
}
async function writeBooks(){
const data = JSON.stringify({"1": [new Book('c1').code, new Book('c2').code]});
await fs.promises.writeFile(file, data, 'utf8');
}
async function getBook(code){
try{
const data = await fs.promises.readFile(file);
const dataOnJsonFile = JSON.parse(data);
return dataOnJsonFile["1"];
} catch (err){
console.log(err)
}
}
writeBooks();
getBook('c1').then(b => console.log(b));
The above problem is that the Books returned from JSON.parse have only data, not methods, and thus I cannot get the code via get code(){}, but only as public parameter of class Book as book._code, which however breaks encapsulation (convetion is that _[propery] is private, and there should be appropriate getters/setters). So I made the properties public (and broke encapsulation), because I still don't know, how to assign methods to object created from JSON.
No, the result of async is always Promise. You cannot unwrap it inside async, the client will always have to unwrap it. (so await fs.promises.WriteFile() will unwrap it, but then immediately wrap it back, before async function returns.
as explained above.

Nodejs - array not returning anything

I'm trying to save the answer to my request with axios in an array, but I'm not getting it, is something wrong?
colorList = axios.get(colors);
let codes = [];
for (let i = 0; i < colorList.data.data.colors.length; i++) {
codes[i].push(colorList.data.data.colors[i]);
}
console.log(codes);
The call is asynchronous meaning that you have to wait for your request to complete (or more accurately your promise from axios.get() to resolve) and do something with the result. Your code right now runs synchronously.
colorList = axios.get(colors).then(result =>{
console.log(result)
});
EDIT: Or as a comment above noted, use an async/await setup. Keep in mind that you can't use await in top level code, it can only be used inside an async function
(async () => {
try {
const colorCodes = await axios.get(colors);
} catch (e) {
// handle error
}
})()
If colorList.data.data.colors has values then try
codes.push(colorList.data.data.colors[i]);
As most comments pointed out, the mistake in your code is that you don't await for the async call to be completed.The way that js works when you use async code is that it jumps to the next line immediatelly while the async process continues . That's the point of Async code: You don't want your program to freeze in case of async call delays. I made a similar code example using numbersapi.
var axios = require('axios');
const axiosCallToArray = async () => {
const result = await axios.get('http://numbersapi.com/42');
const wordsArray = result.data.split(' '); // here i create an array breaking the sentence (returned as result from axios) into words.Every word is an element of the new array
console.log(wordsArray);
};
axiosCallToArray(); //now console.log works fine. This is valid also for your code

Recursion with an API, using Vanilla JS

I'm playing with the Rick and Morty API and I want to get all of the universe's characters
into an array so I don't have to make more API calls to work the rest of my code.
The endpoint https://rickandmortyapi.com/api/character/ returns the results in pages, so
I have to use recursion to get all the data in one API call.
I can get it to spit out results into HTML but I can't seem to get a complete array of JSON objects.
I'm using some ideas from
Axios recursion for paginating an api with a cursor
I translated the concept for my problem, and I have it posted on my Codepen
This is the code:
async function populatePeople(info, universePeople){ // Retrieve the data from the API
let allPeople = []
let check = ''
try {
return await axios.get(info)
.then((res)=>{
// here the current page results is in res.data.results
for (let i=0; i < res.data.results.length; i++){
item.textContent = JSON.stringify(res.data.results[i])
allPeople.push(res.data.results[i])
}
if (res.data.info.next){
check = res.data.info.next
return allPeople.push(populatePeople(res.data.info.next, allPeople))
}
})
} catch (error) {
console.log(`Error: ${error}`)
} finally {
return allPeople
}
}
populatePeople(allCharacters)
.then(data => console.log(`Final data length: ${data.length}`))
Some sharp eyes and brains would be helpful.
It's probably something really simple and I'm just missing it.
The following line has problems:
return allPeople.push(populatePeople(res.data.info.next, allPeople))
Here you push a promise object into allPeople, and as .push() returns a number, you are returning a number, not allPeople.
Using a for loop to push individual items from one array to another is really a verbose way of copying an array. The loop is only needed for the HTML part.
Also, you are mixing .then() with await, which is making things complex. Just use await only. When using await, there is no need for recursion any more. Just replace the if with a loop:
while (info) {
....
info = res.data.info.next;
}
You never assign anything to universePeople. You can drop this parameter.
Instead of the plain for loop, you can use the for...of syntax.
As from res you only use the data property, use a variable for that property only.
So taking all that together, you get this:
async function populatePeople(info) {
let allPeople = [];
try {
while (info) {
let {data} = await axios.get(info);
for (let content of data.results) {
const item = document.createElement('li');
item.textContent = JSON.stringify(content);
denizens.append(item);
}
allPeople.push(...data.results);
info = data.info.next;
}
} catch (error) {
console.log(`Error: ${error}`)
} finally {
section.append(denizens);
return allPeople;
}
}
Here is working example for recursive function
async function getAllCharectersRecursively(URL,results){
try{
const {data} = await axios.get(URL);
// concat current page results
results =results.concat(data.results)
if(data.info.next){
// if there is next page call recursively
return await getAllCharectersRecursively(data.info.next,results)
}
else{
// at last page there is no next page so return collected results
return results
}
}
catch(e){
console.log(e)
}
}
async function main(){
let results = await getAllCharectersRecursively("https://rickandmortyapi.com/api/character/",[])
console.log(results.length)
}
main()
I hesitate to offer another answer because Trincot's analysis and answer is spot-on.
But I think a recursive answer here can be quite elegant. And as the question was tagged with "recursion", it seems worth presenting.
const populatePeople = async (url) => {
const {info: {next}, results} = await axios .get (url)
return [...results, ...(next ? await populatePeople (next) : [])]
}
populatePeople ('https://rickandmortyapi.com/api/character/')
// or wrap in an `async` main, or wait for global async...
.then (people => console .log (people .map (p => p .name)))
.catch (console .warn)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script>/* dummy */ const axios = {get: (url) => fetch (url) .then (r => r .json ())} </script>
This is only concerned with fetching the data. Adding it to your DOM should be a separate step, and it shouldn't be difficult.
Update: Explanation
A comment indicated that this is hard to parse. There are two things that I imagine might be tricky here:
First is the object destructuring in {info: {next}, results} = <...>. This is just a nice way to avoid using intermediate variables to calculate the ones we actually want to use.
The second is the spread syntax in return [...results, ...<more>]. This is a simpler way to build an array than using .concat or .push. (There's a similar feature for objects.)
Here's another version doing the same thing, but with some intermediate variables and an array concatenation instead. It does the same thing:
const populatePeople = async (url) => {
const response = await axios .get (url)
const next = response .info && response .info .next
const results = response .results || []
const subsequents = next ? await populatePeople (next) : []
return results .concat (subsequents)
}
I prefer the original version. But perhaps you would find this one more clear.

async-await with console.log works but when I try to use the return statement I'm getting a promise back instead?

I'm hoping somebody can point out the error of my ways here.
I have two functions at the moment. One is getData and it's an async function that simply makes an API call requesting data. The second function is getRandomCategories that encapsulates the getData function call and holds the value of that async operation in a variable called res. The rest of the code within getRandomCategories manipulates the response data to an array of numbers where each number represents a category.
When I use the debugger statement in the getRandomCategories function (right before the return statement within the try block) I'm getting the data type I'm expecting from my variable named apiCallCategoryArray - it's an array of numbers each representing a category. Life is good.
Here's what I'm not understanding: If you look at the two function calls towards the bottom of the snippet (test() and testAgain() they're essentially the same functions but just with different names so I can compare them side-by-side) I'm able to console.log(res) in test() with the expected return value (an array of numbers) but when I try to return res (in testAgain()) the variable myData2 does NOT contain an array of numbers (as what I'm expecting it to contain) instead it contains: Promise { <state>: "pending" }
Here's my code below:
async function getData(endpoint, query, value) {
return await axios.get(
`http://jservice.io/api/${endpoint}?&${query}=${value}`
)
}
// createa a function that will return 6 random categories
async function getRandomCategories(data) {
try {
const res = await getData('categories', 'count', 50)
const data = res.data;
const categories = filterCategoryData(data); // I'm filtering for categories
const categoryIdArr = mapCategoryIds(categories); // an array of just category Ids
const shuffledCategoryIds = shuffle(categoryIdArr); // shuffles the array
const apiCallCategoryArray = takeFirstXItems(shuffledCategoryIds, 6); // takes 6 items
debugger // values are as expected
return apiCallCategoryArray
} catch (err) {
console.log(err);
}
}
// this logs what my expected return value should be
async function test() {
const res = await getRandomCategories()
console.log(res) // Array(6) [ 11518, 11537, 11533, 11512, 11542, 11506 ]
}
// But when I try to use the return statement so I can use the array
// I'm getting a promise back. This NOT my expected return value??
async function testAgain() {
const res = await getRandomCategories()
return res // return statement instead of console.log()
}
const myData = test() // the console.log within the test function logs the expected data type
console.log(myData) // but if I console.log myData it logs: Promise { <state>: "pending" }
const myData2 = testAgain() // same function but just a different name but this time I'm using a return statement instead of console.log
console.log(myData2) // Promise { <state>: "pending" }
My question is: why am I able to console.log(res) with the expected return value in test()
but when I use the return statement (like in testAgain()) I'm getting a Promise { : "pending" } instead of the array of numbers like I'm expecting. Where do I tweak my code so that my variable holds an array of numbers instead of the Promise?
Thanks in advance for everyone's time.
const data = res.data; should be const data = await res.data; in the getRandomCategories function. Also const myData2 = testAgain() should be const myData2 = await testAgain() but as it is top level code and await needs an async function, you could wrap it into an self-invoking function or use then/catch.
More info about async/await here.

Understand Vue and Return and Async Await

I am new to Javascript and Vue and I am having a hard time wrapping my head around return, async and await work together. I come from a Python background and JS syntax is quite different
So... some background to the problem....I'm building a Vue blog and creating multiple Vuex stores using module mode. I am also creating a function to retrieve data from Prismic.
./store/blog.js
import {MyFunctions} from "../plugins/myfunctions.js";
export const actions = {
async retrievePosts() {
console.log("HELLO")
return MyFunctions.MyFunction("blog_post");
}
}
./plugins/myfunctions.js
import Prismic from "prismic-javascript";
import PrismicDom from "prismic-dom" //importing the Dom
import PrismicConfig from "../prismic.config.js";
export const MyFunctions = {
MyFunction: async function (doctype) {
console.log("Before")
const api = await Prismic.getApi(PrismicConfig.apiEndpoint)
let blog_post = {}
const results = await api.query(
Prismic.Predicates.at("document.type", doctype),
{ lang: "en-us" } //This is a Prismic query option
)
console.log("After")
result = results.results
return result;
}
};
Heres my question:
In blog.js, if I remove the word "return" in front of MyFunctions.MyFunction("blog_post") , the await in myfunctions.js do not get activated. Why?
I say this because without the return, "Before" is console logged but "After" is not and nothing is returned.
A further question for my enlightenment:
Where does return MyFunctions.MyFunction("blog_post") return to? So the data is returned to retrievePosts() but it is part of a {} which is a javascript object I believe? So does it become like a property inside {}?
Ans 1:You are actually returning a function to the caller of retrievePosts() in async mode. By removing return, function will be executed but it don't make any effect to the caller of retrievePosts() function.
Ans 2:The MyFunctions.MyFunction("blog_post") is returned to the caller of retrievePosts() function.

Categories