Pass an Array as a query String Parameter node.js - arrays

How can I pass an array as a query string parameter?
I've tried numerous ways including adding it to the path but i'm not able to pull the array on the back end.
If I hard code the array it works fine, but when I try to pass the array from my front end to the backend it does not work properly.
Can anyone point me in the right direction?
FrontEnd
function loadJob() {
return API.get("realtorPilot", "/myTable/ListJobs", {
'queryStringParameters': {
radius,
availableServices,
}
});
BackEnd
import * as dynamoDbLib from "./libs/dynamodb-lib";
import { success, failure } from "./libs/response-lib";
export async function main(event, context) {
const data = {
radius: event.queryStringParameters.radius,
availableServices: event.queryStringParameters.availableServices,
};
// These hold ExpressionAttributeValues
const zipcodes = {};
const services = {};
data.radius.forEach((zipcode, i) => {
zipcodes[`:zipcode${i}`] = zipcode;
});
data.availableServices.forEach((service, i) => {
services[`:services${i}`] = service;
});
// These hold FilterExpression attribute aliases
const zipcodex = Object.keys(zipcodes).toString();
const servicex = Object.keys(services).toString();
const params = {
TableName: "myTable",
IndexName: "zipCode-packageSelected-index",
FilterExpression: `zipCode IN (${zipcodex}) AND packageSelected IN (${servicex})`,
ExpressionAttributeValues : {...zipcodes, ...services},
};
try {
const result = await dynamoDbLib.call("scan", params);
// Return the matching list of items in response body
return success(result.Items);
} catch (e) {
return failure(e.message);
}
}

Pass a comma seperated string and split it in backend.
Example: https://example.com/apis/sample?radius=a,b,c,d&availableServices=x,y,z
And in the api defenition split the fields on comma.
const data = {
radius: event.queryStringParameters.radius.split(','),
availableServices: event.queryStringParameters.availableServices.split(',')
};

Related

Typescript: Array is empty after calling and passing it to function

Hi I am building function to recursively "denest" a object of following interface:
export interface IUnit {
code: string
artifacts: IArtifact[]
units: IUnit[]
}
The idea is that I have a separate array that I returns with every immersion and after each return the returned array is "pushed" to local array and so on...
the function is as following:
const denestList = async (incomingUnit: IUnit): Promise<{ allUnits: IUnit[], allArtifacts: IArtifact[] }> => {
var units = [incomingUnit];
var artifacts = [...incomingUnit.artifacts];
//Array is full
console.log(unit.units)
//Array is empty
console.log(unit.units.length)
console.log([...unit.units])
console.log(Array.from(unit.units)?.length)
for (unit of incomingUnit.units) {
console.log(unit.code)
//Recursion happens here.
var result = await denestList(unit)
units.push(...result.allUnits)
artifacts.push(...result.allArtifacts)
}
return { allUnits: units, allArtifacts: artifacts }
}
The problem is that for (unit of incomingUnit.units) never happens. When I log unit.units it shows array full of IArtifact[], but when I run console.log(unit.units.length) it return 0.
Here is how to "denestList" function is called:
useEffect(() => {
asyncStart(unit)
}, []);
const asyncStart = async (mainUnit: IUnit) => {
var result = await denestList(mainUnit);
setAllUnits(result.allUnits)
setAllArtifacts(result.allArtifacts)
}
I would really appreciate any help. Thank you in advance

String to array (object) Angular TS 12

I have a CSV file (local), converted it to a string, part of the string is like:
44,"3845657"
51,"3847489"
1,"3888510"
79,"3840471"
57,"3864492"
After I receive input number (first value), I want to match it to the second value (string).
so if input is 51, I want to be able to return 3847489.
No headers in the csv.
CSV to string:
fetchData() {
fetch('../../../assets/static/mapping.csv')
.then(response => response.text())
.then(data => {
// Do something with your data
console.log(data);
this.mappingCSV = data;
});
}
outputs:
44,"3845657"
51,"3847489"
1,"3888510"
79,"3840471"
57,"3864492"
Other ways to convert a csv to an array of objects is also welcome, not married with my csv to string method.
I'm using HTTPClient in this example which is a built-in service class available in Angular. Here's how to use HTTPClient of Angular for you to read and know its benefits.
In my .ts file, I split the text-converted csv first for any newline. Then I added a loop in which I split the text by comma and pushed the necessary details to the new csvArray.
export class SampleComponent {
public csvArr: CsvArray[] = [];
constructor(private http: HttpClient) {
this.http.get('assets/csv.csv', {
responseType: 'text'
}).subscribe(
(data) => {
const csvToRowArray = data.split('\n');
console.log(csvToRowArray);
for (let index = 0; index < csvToRowArray.length; index++) {
const row = csvToRowArray[index].split(',');
this.csvArr.push(new CsvArray(parseInt(row[0], 10), row[1]));
}
console.log(this.csvArr);
},
(error) => {
console.log(error);
}
);
}
}
export class CsvArray {
id: number;
text: string;
constructor(id: number, text: string) {
this.id = id;
this.text = text;
}
}
I created a stackblitz so that you can check my implementation.

Array returning undefined in Vue from indexedDB

The console.log in my indexedDB works and returns the result that I want; an array of objects that is currently in the store. So my code there is correct. I'm going to use this information to build a table. However, in Vue it returns undefined. I'm trying to set the leagues array in Vue to equal the result array that indexedDB gives, but it returns undefined.
This is the code in Vue:
<script>
import * as db from "../db/db.js";
export default {
name: "leaguesTable",
data: function() {
return {
leagues: []
};
},
created: function() {
this.leagues = db.getAllInStore("meta", "leagues");
console.log(this.leagues);
}
};
</script>
This is my indexedDB code:
function getAllInStore(dbName, storeName) {
let db;
var request = indexedDB.open(dbName, 1);
request.onerror = function(event) {
alert("Database error" + event.target.errorCode);
};
request.onsuccess = function(event) {
db = event.target.result;
let tx = db.transaction(storeName, "readonly");
tx.onerror = function(event) {
alert("Transaction error" + event.target.errorCode);
};
let store = tx.objectStore(storeName);
let result = store.getAll();
tx.oncomplete = function() {
alert("This should work");
console.log(result.result);
return result.result;
};
};
}
In your created hook you need to make sure to return a value from db.getAllInStore so that this.leagues assumes that value.
Next, In the getAllInStore function result.result gets returned from the transaction but not within onComplete or the enclosing getAllInStore function.
Since the db uses event hooks like onError and onComplete, Returning the request won't give you the result of the call to the db. In order to return the value of an async operation in javascript, typically callbacks or promises are used. The example below makes use of promises to solve the issue.
Vue JS:
<script>
import * as db from "../db/db.js";
export default {
name: "leaguesTable",
data: function() {
return {
leagues: []
};
},
// async is necessary to use await
created: async function() {
// await is es2016 syntactic sugar for retrieving the value of a promise
this.leagues = await db.getAllInStore("meta", "leagues");
console.log(this.leagues);
}
};
</script>
IndexDB:
function getAllInStore(dbName, storeName) {
// resolve param is a function that signifies a successful operation
// reject param is a function that should be called whenever a check or error occurs
return new Promise((resolve, reject) => {
let db;
let request = indexedDB.open(dbName, 1);
request.onerror = (event) => reject(event);
request.onsuccess = (event) => {
db = event.target.result;
let tx = db.transaction(storeName, "readonly");
request.onerror = (event) => reject(event);
let store = tx.objectStore(storeName);
let result = store.getAll();
tx.oncomplete = (result) => resolve(result.result);
};
});
}
Further Reading:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises

relay prisma graphql update store

I am trying to get prisma and relay working. Here's my repo:
https://github.com/jamesmbowler/prisma-relay-todo
It's a simple todo list. I am able to add the todos, but the ui does not update. When I refresh, the todo is there.
All of the examples of updating the store, that I can find, use a "parent" to the object that is being updated / created.
See https://facebook.github.io/relay/docs/en/mutations.html#using-updater-and-optimisticupdater
Also, the "updater configs" also requires a "parentID". https://facebook.github.io/relay/docs/en/mutations.html#updater-configs
From relay-runtime's RelayConnectionHandler.js comment here:
https://github.com/facebook/relay/blob/master/packages/relay-runtime/handlers/connection/RelayConnectionHandler.js#L232
* store => {
* const user = store.get('<id>');
* const friends = RelayConnectionHandler.getConnection(user, 'FriendsFragment_friends');
* const edge = store.create('<edge-id>', 'FriendsEdge');
* RelayConnectionHandler.insertEdgeAfter(friends, edge);
* }
Is it possible to update the store without having a "parent"? I just have todos, with no parent.
Again, creating the record works, and gives this response:
{ "data" : {
"createTodo" : {
"id" : "cjpdbivhc00050903ud6bkl3x",
"name" : "testing",
"complete" : false
} } }
Here's my updater function
updater: store => {
const payload = store.getRootField('createTodo');
const conn = ConnectionHandler.getConnection(store.get(payload.getDataID()), 'Todos_todoesConnection');
ConnectionHandler.insertEdgeAfter(conn, payload, cursor);
},
I have done a console.log(conn), and it is undefined.
Please help.
----Edit----
Thanks to Denis, I think one problem is solved - that of the ConnectionHandler.
But, I still can't get the ui to update. Here's what I've tried in the updater function:
const payload = store.getRootField('createTodo');
const clientRoot = store.get('client:root');
const conn = ConnectionHandler.getConnection(clientRoot, 'Todos_todoesConnection');
ConnectionHandler.createEdge(store, conn, payload, 'TodoEdge');
I've also tried this:
const payload = store.getRootField('createTodo');
const clientRoot = store.get('client:root');
const conn = ConnectionHandler.getConnection(clientRoot, 'Todos_todoesConnection');
ConnectionHandler.insertEdgeAfter(conn, payload);
My data shape is different from their example, as I don't have the 'todoEdge', and 'node' inside my returned data (see above).
todoEdge {
cursor
node {
complete
id
text
}
}
How do I getLinkedRecord, like this?
const newEdge = payload.getLinkedRecord('todoEdge');
If query is the parent, the parentID will be client:root.
Take a look at this: https://github.com/facebook/relay/blob/1d72862fa620a9db69d6219d5aa562054d9b93c7/packages/react-relay/classic/store/RelayStoreConstants.js#L18
Also at this issue: https://github.com/facebook/relay/issues/2157#issuecomment-385009482
create a const ROOT_ID = 'client:root'; and pass ROOT_ID as your parentID. Also, check the name of your connection on the updater, it has to be exactly equal to the name where you declared the query.
UPDATE:
Actually, you can import ROOT_ID of relay-runtime
import { ROOT_ID } from 'relay-runtime';
UPDATE 2:
Your edit was not very clear for me, but I will provide you an example of it should work ok? After your mutation is run, you first access its data by using getRootField just like you are doing. So, if I have a mutation like:
mutation UserAddMutation($input: UserAddInput!) {
UserAdd(input: $input) {
userEdge {
node {
name
id
age
}
}
error
}
}
You will do:
const newEdge = store.getRootField('UserAdd').getLinkedRecord('userEdge');
connectionUpdater({
store,
parentId: ROOT_ID,
connectionName: 'UserAdd_users',
edge: newEdge,
before: true,
});
This connectionUpdater is a helper function that looks likes this:
export function connectionUpdater({ store, parentId, connectionName, edge, before, filters }) {
if (edge) {
if (!parentId) {
// eslint-disable-next-line
console.log('maybe you forgot to pass a parentId: ');
return;
}
const parentProxy = store.get(parentId);
const connection = ConnectionHandler.getConnection(parentProxy, connectionName, filters);
if (!connection) {
// eslint-disable-next-line
console.log('maybe this connection is not in relay store yet:', connectionName);
return;
}
const newEndCursorOffset = connection.getValue('endCursorOffset');
connection.setValue(newEndCursorOffset + 1, 'endCursorOffset');
const newCount = connection.getValue('count');
connection.setValue(newCount + 1, 'count');
if (before) {
ConnectionHandler.insertEdgeBefore(connection, edge);
} else {
ConnectionHandler.insertEdgeAfter(connection, edge);
}
}
}
Hope it helps :)

How to for loop all documents in a collection - Azure CosmosDB - Nodejs

I have looked around at a few answers/questions regarding this issue but yet to find a solution.
I have a collection with documents (simplified) as such:
{
"id": 123
"stuff": "abc"
"array":[
{
"id2":456
"properties": [
{
"id3": 789
"important": true
}
]
}
]
}
I want to check for each document in my collection, for each array object within array, for each properties, if it has important: true for example. Then return:
"id": 123
"id2": 456
"id3": 789
I have tried using:
client.queryDocuments(self.collection._self, querySpec).toArray(function(err, results) {
if (err) {
callback(err);
} else {
callback(null, results[0]);
}
});
But the issue is an array has a maximum character limit. If my collection has millions of documents, this would presumably be exceeded. (Javascript Increase max array size)
Or, am I misunderstanding the above question? Is it talking about the number of objects in an array (of which, each can have unlimited object character length?)
Thus I am looking a for loop-esque solution, where each document is returned, I do my analysis, then move to then next/do them in parallel.
Any insight would be greatly appreciated.
But the issue is an array has a maximum character limit. If my
collection has millions of documents, this would presumably be
exceeded. (Javascript Increase max array size)
Based on my research,the longest possible array in js could have 232-1 = 4,294,967,295 = 4.29 billion elements. However, it is perfectly enough to meet your millions data volume requirements. In addition,you can't query such huge volume data directly surely,that's impossible you do that.
Whether about throughput constraints(RUs settings) or query efficiency factors, you should consider batching large volumes of data anyway.
Thus I am looking a for loop-esque solution, where each document is
returned, I do my analysis, then move to then next/do them in
parallel.
Maybe you could use v2 js sdk for cosmos db sql api.Please refer to the sample code:
const cosmos = require('#azure/cosmos');
const CosmosClient = cosmos.CosmosClient;
const endpoint = "https://***.documents.azure.com:443/"; // Add your endpoint
const masterKey = "***"; // Add the masterkey of the endpoint
const client = new CosmosClient({ endpoint, auth: { masterKey } });
const databaseId = "db";
const containerId = "coll";
async function run() {
const { container, database } = await init();
const querySpec = {
query: "SELECT r.id,r._ts FROM root r"
};
const queryOptions = {
maxItemCount : -1
}
const queryIterator = await container.items.query(querySpec,queryOptions);
while (queryIterator.hasMoreResults()) {
const { result: results, headers } = await queryIterator.executeNext();
console.log(results)
console.log(headers)
//do what you want to do
if (results === undefined) {
// no more results
break;
}
}
}
async function init() {
const { database } = await client.databases.createIfNotExists({ id: databaseId });
const { container } = await database.containers.createIfNotExists({ id: containerId });
return { database, container };
}
run().catch(err => {
console.error(err);
});
More details about continuation token ,please refer to my previous case.Any concern,please let me know.
I am using Cosmos DB SQL API Node.js library. I am unable to find the Continuation Token from this library so that I can return it to client. The idea is to get it back from the client for the next pagination request.
I have a working code which iterates multiple times to get all the documents. What changes will be required here to get the continuation token?
function queryCollectionPaging() {
return new Promise((resolve, reject) => {
function executeNextWithRetry(iterator, callback) {
iterator.executeNext(function (err, results, responseHeaders) {
if (err) {
return callback(err, null);
}
else {
documents = documents.concat(results);
if (iterator.hasMoreResults()) {
executeNextWithRetry(iterator, callback);
}
else {
callback();
}
}
});
}
let options = {
maxItemCount: 1,
enableCrossPartitionQuery: true
};
let documents = []
let iterator = client.queryDocuments( collectionUrl, 'SELECT r.partitionkey, r.documentid, r._ts FROM root r WHERE r.partitionkey in ("user1", "user2") ORDER BY r._ts', options);
executeNextWithRetry(iterator, function (err, result) {
if (err) {
reject(err)
}
else {
console.log(documents);
resolve(documents)
}
});
});
};

Resources