How to do pagination on channels in twilio-programmable-chat? - javascript

I am using twilio javascript sdk for twilio-programmable-chat.
And I want to apply pagination to my channels result but I am not able to figure it out.
Here is my current code.
this.chatClient.getUserChannelDescriptors().then(paginator => {
// All channels are fetched
})
I tried to pass a pageSize similar to how getMessages(10) work but it didn't work.
this.chatClient.getUserChannelDescriptors(10).then(paginator => {
// The result was same, it fetched all the channels instead of just 10
})
I am looking for a example that how pagination can be done on channels.
Thanks.

I've finally found a way how to do it.
It should be done recursively since we get the initial list by calling getUserChannelDescriptors() but then the rest of the records can be fetched by calling nextPage();
async function processChannels(paginator) {
// Now, if hasNextPage is true
// call nextPage() to get the records instead of getUserChannelDescriptors()
if (paginator.hasNextPage) {
const nextPaginator = paginator.nextPage();
processChannels(nextPaginator);
} else {
console.log("END OF RECORDS");
}
}
async function getChannels() {
const paginator = await chatClient.getUserChannelDescriptors();
// Initiate the recursive function
if (paginator.items) {
await processChannels(paginator);
}
}
And this is what you will get in each call.

According to the documentation, the getUserChannelDescriptors method doesn't take any arguments.
But you shouldn't have to do pagination manually, since the method returns a Promise.<Paginator.<ChannelDescriptor>> type..which means you should be able to get access to the Pagination features twilio provides.
Your paginator.items should have only the items in a single page.
EDIT: Basically the point is that your first snippet is correct. Unfortunately, twilio is not open source so I cannot check where they have defined the page_size exactly. But I would encourage you to create say a hundred mock channels, and then check the size of the paginator.items array.
Try this:
this.chatClient.getUserChannelDescriptors().then(paginator => {
console.log(paginator.items, paginator.hasNextPage(), paginator.hasPrevPage());
})
The documentation for the Paginator class is here

Related

Is it possible to use a Firestore transaction to update an object retrieved before the transaction?

Below is my code summarized, my question is quite simple, I actually already have the object order loaded before all this code, but I am afraid the update on this object will not be handled inside the transaction if I don't get it again inside it.
So my question is, do I have to retrieve again my order object inside the transaction?
try {
await runTransaction(db, async (transaction) => {
// First object to update
const dailyCountSnap = await transaction.get(dailyCountRef);
let dailyCount;
if (dailyCountSnap.exists) {
dailyCount = dailyCountSnap.data();
} else {
return Promise.reject(`ERROR: No daily count found`);
}
/* ... Code to update dailyCount ... */
transaction.set(dailyCountRef, {...});
// Second object to update
const orderSnap = await transaction.get(orderRef);
let order;
if (orderSnap.exists) {
order = orderSnap.data();
} else {
return Promise.reject(`ERROR: No order found`);
}
/* ... Code to update order ... */
transaction.update(orderRef, {...});
});
} catch (e) {
functions.logger.error(e);
}
A transaction on Firestore only has context on data that was read within that transaction.
From the documentation on optimistic concurrency controls:
In the Mobile/Web SDKs, a transaction keeps track of all the documents you read inside the transaction.
and
In the server client libraries, transactions place locks on the documents they read.
So if you write a document that you didn't read before, the write operation could be overwriting data in the document and not meet the isolation guarantee of the transaction. The SDK might even raise an error when you try this, although I didn't check that.

How to use if else loop in Dialogflow for showing results

I have Javascript code for Dialogflow doing project on Google Actions. For this code if answer is in database means it will answer otherwise it is exiting out of app. So, I want to use else loop for this code plz help me
function handleCompanyDetails(agent){
const RegNo = agent.parameters.RegNo;
var ref8 = admin.database().ref().child("Table/");
var query8 = ref8.orderByChild("RegNo").equalTo(RegNo);
return query8.once("value")
.then(function(snapshot) {
snapshot.forEach(function(child) {
if( !snapshot.exists() ){
// There are no results, say so
agent.add("There are no results for that account.");
} else {
// ... Do something with the data
agent.add(`The student placed in ` + child.val().CompanyName);
}
});
});
}
While you can use a loop to show results, there are a few problems with how you've done to, and possibly even with what you're trying to return.
First - Dialogflow requires you to return a Promise from any function that makes an asynchronous call, such as a call to the Firebase database. You're currently using the callback method. You should switch to using once() that returns a Promise instead, so that might look something like this:
return query8.once("value")
.then( snapshot => {
// working with snapshot goes here
})
.catch( err => {
console.error(err);
agent.add("There was a problem.");
});
The second is how you work with snapshot itself. If you're expecting multiple results, you should be aware that you can only call agent.add() with a text message twice and one basic card. If you want multiple cards, you may want to use a list or carousel instead.
If you are expecting only one response indexed off the RegNo, which it looks like you may be, then you should just include that as part of the path and get the value of the snapshot. You wouldn't need a loop in this case.
Update based on updated code.
As you noted, you're not sending anything if there are no results, so the Action exits with an error.
The easiest way to do this is to use snapshot.exists() to check if there are any results in the snapshot. If there aren't any, then you can return an error. That might look something like
return query8.once("value")
.then(function(snapshot) {
if( !snapshot.exists() ){
// There are no results, say so
agent.add("There are no results for that account.");
} else {
// ... Do something with the data
}
});
// ...
If you do have results, you still have the issue that you may be sending back too many replies. You can only have one agent.add() with a message to be spoken (or two, at the most, but don't do that) and only one Card, unless you use a List or Carousel. So it would be better for you to build that message inside the loop.
Use .then() while doing operations on snapshot. Because .once() only triggers one time so if data is available meaning.then() will be executed and you can exit it using .catch(). check the code below.
function handleCompanyDetails(agent){
const RegNo = agent.parameters.RegNo;
var ref8 = admin.database().ref().child("Table/");
var query8 = ref8.orderByChild("RegNo").equalTo(RegNo);
return query8.once("value")
.then(function(snapshot) {
snapshot.forEach(function(child) {
agent.add(`The student placed in ` + child.val().CompanyName);
agent.add(new Card({
title: ` Name:${child.val().Studentname}
Reg No: ${child.val().RegNo}
Offer Date: ${child.val().OfferDate} `,
imageUrl: '',
text: `Thanks for using πŸ’\n ${child.val().FirstName} πŸ’`,
buttonText: '.com'
})
})
})
.catch( // throw some error)
}
you can read more here, https://firebase.google.com/docs/database/web/read-and-write

Promise inside promise don't wait Axios finishing

I have a trouble. I receive many objects where I mapping them and I make a external consult using axios and save the return, let's the code:
let savedClients = Object.entries(documents).map(personDocument => {
let [person, document] = personDocument
documentFormated = document
documentNumbers = document.replace(/\D/g, '')
return ConsultDocuments.getResponse(documentNumbers).then(resultScore => { // Calling the axios
const info = { ...resultScore }
return Save.saveClient(info)
})
})
Promise.all(savedClients).then(results => {
console.log(results) // Come only one document, repeted with the total documents passed in map
})
The problem is when it realized the all map first and then make the consults with only the last result many time (the total of documents passed)
This code is legacy and use async/await don't work (serious, if i don't stay here)
I'am tried N ways to make this, and with the libary Q(), it's make the map in correcty order but it's doesn't wait the axios, and all results come with "pending"
Thanks!

How do I implement a find-or-create pattern in firestore

The firestore api has me a little mixed up in trying to have a repeatable pattern for find-or-create style functions. I'd like the canonical version to look like this:
// returns a promise resolving to a DocumentSnapshot (I think??)
function findOrCreateMyObject(myObject) {
return findMyObject(myObject.identifier).then(documentSnapshot => {
return (documentSnapshot)? documentSnapshot : createMyObject(myObject);
});
};
I'm not sure if DocumentSnapshot is the appropriate return from this, but I figure the caller may want to inspect or update the result, like this:
return findOrCreateMyObject({ identifier:'foo' }).then(documentSnapshot => {
console.log(documentSnapshot.data.someProperty);
return documentSnapshot.ref.update({ someProperty:'bar' });
});
Assuming I am right about that (please tell me if not), it means that both the find and create functions must return a DocumentSnapshot. This is easy enough for the find...
function findMyObject(identifier) {
let query = db.collection('my-object-collection').where('identifier','=='identifier);
return query.get().then(querySnapshot => {
return (querySnapshot.docs.length)? querySnapshot.docs[0] : null;
});
}
...but rather awkward for the create, and the the gist of my problem. I'd want to write create like this....
function createMyObject(myObject) {
// get db from admin
let collectionRef = db.collection('my-object-collection');
return db.collection('my-object-collection').doc().set(myObject);
}
But I cannot because DocumentReference set() resolves to a "non-null promise containing void". Void? I must read back the object I just wrote in order to get a reference to it? In other words, my idealized create needs to be rewritten to be slower and clunkier...
function createMyObject(myObject) {
// get db from admin
let collectionRef = db.collection('my-object-collection');
return db.collection('my-object-collection').doc().set(myObject).then(() => {
// must we query the thing just written?
return findMyObject(myObject.identifier); // frowny face
});
}
This makes my generic create longer (and unnecessarily so when doing just a create). Please tell me:
is DocumentSnapshot the right "currency" for these functions to traffic in?
Am I stuck with a set() and then another query when creating the new object?
Thanks!
EDIT As an example of where I would apply this, say I have customers, uniquely identified by email, and they have a status: 'gold', 'silver' or 'bronze'. My CRM system decides that someone identifying himself as doug#stevenson.com deserves 'silver' status. We don't know at this point wither Mr. Stevenson is a current customer, so we do a find-or-create...
findOrCreateCustomer({ email:'doug#stevenson.com' }).then(customer => {
customer.update({ status:'silver' });
});
I wouldn't just create, because the customer might exist. I wouldn't just update, because the customer might not exist, or might not meet some other criterion for the update.

How to wait for all dynamic number of forks to complete with redux-saga?

I'm trying to use redux saga to query a number of rest endpoints to get a human readable name associated with each discovered network, to fill a dropdown list with selectable networks.
I'm having trouble doing this, my forking is not working. I keep getting the error message:
TypeError: __webpack_require__.i(..) is not a function(...)
Every example using all() I've found online use call and know ahead of time every request being made. However, judging from the API I tried something like this:
const pendingQueries = [];
for(networkId in discoveredNetworks) {
pendingQueries.push(fork(getApplicationName, networkId);
}
const queryResults = yield all(pendingQueries);
This failed. I've tried a number of other permutations since. From testing I'm able to verify that I can do this:
const results = [];
for(networkId in discoveredNetworks) {
results.push(yield fork(getApplicationName, networkId));
}
and if There is a long enough delay the method will run and complete, though this approach obviously doesn't gaurentee that the forked methods will complete before I use result as I want. Still it seems to confirm the problem is in my use of all.
What is wrong with my all command?
Why don’t you wrap each request in a promise and call them like so:
var promises = []
for(networkId in discoveredNetworks) {
promises.push(new Promise((res, rej) => {
// code from getApplicationName goes here
// call res(result) on success and rej(error) on failure
}));
}
const results = yield call(Promise.all(promises))
I got this to work by giving up on the all() method, which I never got to work as advertised but wasn't really the right method for the job.
For forks I should have been using join() instead. so something along the lines of this:
const pendingQueries = [];
for(networkId in discoveredNetworks) {
pendingQueries.push(yield fork(getApplicationName, networkId);
}
const results = yield join(...pendingQueries);
results.forEach((result) => {
// my logic for handling the response and generating action
}

Categories

Resources