Flutter notifications from firebase messaging is delayed? - node.js

sometime the notification is delayed for no reason and then comes all together iam using
https://pub.dev/packages/flutter_local_notifications
https://pub.dev/packages/firebase_messaging
here is my code from cloud functions ( nodejs )
exports.messageTrigger = functions.firestore.document('/Messages/{messageID}').onCreate(
async (snapshot, context) => {
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var currentRoomUsers = snapshot.data().members;
currentRoomUsers.forEach( (userID) => {
db.collection('Users').doc(userID).get().then(async(doc)=>{
if(doc.exists && doc.id != snapshot.data().senderID){
const message = {
data: {
title: `New message from ${capitalizeFirstLetter(snapshot.data().room)}`,
body: snapshot.data().type == 'm.text' ? 'Sent a new message' : snapshot.data().type == 'm.start'? 'Invited you for a call' : snapshot.data().type == 'm.image' ? 'Sent an image' : 'Sent a new message'
},
tokens: doc.data()['Device_token'],
android: {
priority: 'high',
},
priority: "high",
}
await admin.messaging().sendMulticast(message);
}else {
console.log("No such document!");
}
}).catch((error)=>{
console.log("Error getting document:", error);
});
}
);
}
);

Firestore documents are fetched asynchronously and the sendMulticast() statement here may run before all the documents are fetched. Also, you must terminate Cloud Functions by returning a Promise. Since you are using an async function, try refactoring the code with async-await syntax as shown below:
exports.messageTrigger = functions.firestore
.document("/Messages/{messageID}")
.onCreate(async (snapshot, context) => {
try {
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
const currentRoomUsers = snapshot.data().members;
// use Promise.all() to fetch all documents
const customRoomUsersSnap = await Promise.all(
currentRoomUsers.map((user) =>
db.collection("Users").doc(user).get()
)
);
const messagePromises = [];
// Iterate over all documents and add a message for every existing document
customRoomUsersSnap.forEach((userSnap) => {
if (userSnap.exists) {
const message = {
data: {
title: `New message from ${capitalizeFirstLetter(
snapshot.data().room
)}`,
body:
snapshot.data().type == "m.text"
? "Sent a new message"
: snapshot.data().type == "m.start"
? "Invited you for a call"
: snapshot.data().type == "m.image"
? "Sent an image"
: "Sent a new message",
},
tokens: userSnap.data()["Device_token"],
android: {
priority: "high",
},
priority: "high",
};
messagePromises.push(admin.messaging().sendMulticast(message));
} else {
console.log(`User ${userSnap.ref.id} doc does not exist`);
}
});
// Send all messages simultaneously.
return Promise.all(messagePromises);
} catch (error) {
console.log(error);
// return Promise<null> in case of an error
return null;
}
});

Related

Send web push notifications to specific users conditionally

I am willing to use web-push notifications on my web app. I have already setup serviceWorkers on the front-end(React) and implemented web-push notifications on my backend(NodeJS). Now I just need to send notifications which are user specific, means only specific users should receive those notifications.
For e.g. In my web app's backend I will be receiving some live values. Say, there is a collection named
"users" where all the user's data will be stored. Now these users will have a field named "device" where the user will receive numeric values which will be updated within 40-50 seconds.
Now, their will be a threshold for these values. Say, for e.g. if the value reaches above 200 then that specific user should receive a push notification, letting them know that the device has reached it's limit.
How is it possible for me to create such user specific push notifications where the notification will be sent to only that user who's device value has reached above 200 ?. P.S I am using Mongoose for the database.
FrontEnd code(react.js)
sw.js:
self.addEventListener("notificationclick", function (event) {
// on Notification click
let notification = event.notification;
let action = event.action;
console.log("Notification====>", notification);
if (action === "confirm") {
console.log("Confirm clicked");
notification.close(); // Closes the notifcation
} else {
event.waitUntil(
clients.matchAll().then(function (clis) {
var client = clis.find(function (c) {
return c.visibilityState === "visible";
});
if (client !== undefined) {
// found open window
client.navigate("http://localhost:3000"); // means website opens on the same tab where user is on
client.focus();
} else {
// if client's window was not open
clients.openWindow("http://localhost:3000"); // when browser window is closed, open website
}
notification.close();
})
);
console.log(action); // name of action, basically id
}
});
self.addEventListener("notificationclose", function (event) {
console.log("Notification closed", event);
});
// triggers when we get an incoming push message
self.addEventListener("push", function (event) {
console.log("Push notifications recieved from eventListner", event);
var data = { title: "New!", content: "New things" };
if (event.data) {
// check if payload exists(from backend)
data = JSON.parse(event.data.text()); // recieve payload & store
}
var options = {
body: data.content,
icon: "https://iconarchive.com/download/i90141/icons8/windows-8/Cinema-Avengers.ico",
tag: "id1",
renotify: true,
};
event.waitUntil(self.registration.showNotification(data.title, options));
});
swReg.js:
if ("serviceWorker" in navigator) {
console.log("Registering service worker");
navigator.serviceWorker
.register("/sw.js")
.then(() => {
console.log("Service Worker has been registered");
})
.catch((err) => console.error(err));
}
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function displayConfirmNotification() {
if ("serviceWorker" in navigator) {
const options = {
body: "After subscription managing done",
// icon: "/src/assets/img/pattern_react.png",
// tag:"" ==> in advanced options.
vibrate: [100, 50, 200],
// badge:""
tag: "confirm",
renotify: true,
actions: [
{ action: "confirm", title: "okay" }, // optnl icon:""
{ action: "cancel", title: "cancel" },
],
};
navigator.serviceWorker.ready.then(function (swreg) {
swreg.showNotification("Successfully subscribed sW", options);
});
}
}
function configPushSub() {
if (!("serviceWorker" in navigator)) {
return;
}
var reg;
navigator.serviceWorker.ready
.then(function (swreg) {
// access to sW registration
reg = swreg;
return swreg.pushManager.getSubscription(); // returns any existing subscription
})
.then(function (sub) {
// sub holds the current subscription, if subscription doesn't exist then it returns null
if (sub === null) {
// Create a new subscription
var vapidPublicKey = KEY;
var convertedPublicKey = urlBase64ToUint8Array(vapidPublicKey);
return reg.pushManager.subscribe({
userVisibleOnly: true, // for security
applicationServerKey: convertedPublicKey, // for security & server storage
}); // create new subscription
} else {
// We already have a subscription
}
})
.then(function (newSub) {
// have to pass this subscription(new one) to backend
console.log("New subb =======>", newSub);
return fetch("http://localhost:8000/subscribeToPushNotifications", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
subscriptionObj: newSub,
}),
});
})
.then(function (res) {
if (res.ok) {
displayConfirmNotification();
}
})
.catch(function (e) {
console.log("err while subbing====>", e);
});
}
function askForNotificationPermission() {
Notification.requestPermission(function (result) {
console.log("User's choice", result);
if (result !== "granted") {
console.log("Permission rights not granted");
} else {
configPushSub();
// displayConfirmNotification();
}
});
}
if ("Notification" in window) {
askForNotificationPermission();
}
Backend:
API to subscribe:
exports.subscribeToPushNotifications = async (req, res) => {
const { subscriptionObj } = req.body;
// console.log("Subscription object=====>", subscriptionObj);
if (subscriptionObj != undefined || subscriptionObj != null) {
let newSubscription = new Subscription({
pushSubscription: subscriptionObj,
});
await newSubscription.save();
if (newSubscription) {
console.log(newSubscription);
return res.status(200).send("Subscription made");
} else {
console.log("Not subbed");
return res.status(400).send("Subscription not made");
}
} else {
console.log("Sub obj is null");
return res.status(400).send("Sub obj was null");
}
};
Checking if values are more than the threshold and then sending notification:(For example purposes). This is an example for single user only.
exports.checkStatus = async () => {
schedule.scheduleJob("*/10 * * * * *", async () => {
let subscriptions = await Subscription.find({});
let Email = "james#mail.com";
let findUser = await User.findOne({ Email });
if (findUser) {
if (findUser.device > 200) // findUser.device contains the value
{
for (let i = 0; i < subscriptions.length; i++) { //Notification will be sent to all users which I don't want.
webpush.sendNotification(
subscriptions[i].pushSubscription,
JSON.stringify({
title: "Alert",
content: "Value has reached it's limit",
})
);
}
}
}
});
};
How can I make this work such that only those users who's device's value has gone above 200 will only receive the notification and not all the subscribed users.

Lambda function sometimes returns a null value for data when calling stripe api

I get the following error occasionaly from my lambda function
{
"errorType": "TypeError",
"errorMessage": "Cannot read property 'data' of null",
"stack": [
"TypeError: Cannot read property 'data' of null",
" at /var/task/app.js:86:21",
" at Timeout._onTimeout (/var/task/node_modules/stripe/lib/utils.js:324:13)",
" at listOnTimeout (internal/timers.js:549:17)",
" at processTimers (internal/timers.js:492:7)"
]
}
I am wondering if in my code there is a way if the stripe call is failing (which I think is what is happening) then I can retry , otherwise not sure what to do. Here is my code
// const axios = require('axios')
// const url = 'http://checkip.amazonaws.com/';
const sanityClient = require("#sanity/client");
const client = sanityClient({
projectId: "fdsa...",
dataset: "development",
token: process.env.SANITY_TOKEN_WRITE,
});
const fetch = require("node-fetch");
const stripe = require("stripe")(`${process.env.STRIPE}`);
let response;
/**
*
* Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
* #param {Object} event - API Gateway Lambda Proxy Input Format
*
* Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
* #param {Object} context
*
* Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
* #returns {Object} object - API Gateway Lambda Proxy Output Format
*
*/
exports.lambdaHandler = async (event, context, callback) => {
if (event.httpMethod === "POST") {
response = {
statusCode: 200,
body: JSON.stringify({
message: "hello world",
// location: ret.data.trim()
}),
};
//console.log(event.body);
const payload = JSON.parse(event.body);
async function retrieveProduct() {
const product = await stripe.checkout.sessions.listLineItems(
payload.data.object.id,
{ limit: 5 },
function (err, lineItems) {
console.log(lineItems);
let query;
lineItems.data.map((item) => {
//console.log(item);
//console.log(item.id);
query = `*[_type == "products" && product_id == "${item.price.product}"]`;
//console.log(query);
client.fetch(query, {}).then((documents) => {
//console.log("document");
//console.log(documents);
//console.log(documents[0]._id);
//console.log("document");
documents.forEach((document) => {
client
.patch(document._id) // Document ID to patch
.set({ sold: true }) // Shallow merge
.commit()
.then((result) => {
// console.log(result);
});
});
});
});
}
);
}
async function purchaseRecord() {
const product = await stripe.checkout.sessions.listLineItems(
payload.data.object.id,
{ limit: 5 },
function (err, lineItems) {
//console.log(lineItems);
let arr = [];
lineItems.data.map((item, i) => {
arr.push({
_type: "line_items",
_key: `f83nf893n${i}`,
line_items: item.price.product,
line_items_desc: item.description,
});
//console.log(item);
});
console.log(arr);
const doc = {
_type: "purchases",
cs_id: payload.data.object.id,
customer_id: payload.data.object.customer,
amount_total: payload.data.object.amount_total,
line_items_wrapper: arr,
};
client.create(doc).then((res) => {
console.log(`Purchase was created, document ID is ${res._id}`);
});
}
);
}
purchaseRecord();
retrieveProduct();
}
if (event.httpMethod === "GET") {
try {
// const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: "hello world",
// location: ret.data.trim()
}),
};
} catch (err) {
console.log(err);
return err;
}
}
callback(null, response);
};
The code runs like 90% of the time, but this error happens occasionally.
Thanks ahead of time
Change if block with this and you can get error message instead null
if (event.httpMethod === "GET") {
try {
// const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: "hello world",
// location: ret.data.trim()
}),
};
callback(null, response);
} catch (err) {
console.log(err);
callback(Error(err));
}
}
I don't think this has anything to do with the GET request.
I'm not sure where line 86 is, but I think that sometimes const payload = JSON.parse(event.body); is empty, so you should check if that actually contains a data field before you proceed trying to process it.

Bad request while deploying cloud function in firebase. HTTP Error: 400

I'm trying to deploy cloud function to create push notification (chat messaging) on firebase (Firestore).
But when i'm trying to do this - i'm always getting HTTP Error: 400, The request has errors.
Looks like path of collections is good.
exports.notifyNewMessage = functions.firestore
.document('/chat/{toUserId}/chatRoom/{fromUserId}/chatItems')
.onCreate((docSnapshot, context) => {
const message = docSnapshot.data();
const recipientId = context.params.toUserId; // получатель сообщения
const senderId = context.params.fromUserId; // отправитель сообщения
const senderName = message['username'];
if (recipientId === senderId) {
} else {
return admin.forestore().doc('tokens/' + recipientId).get().then(userDoc => {
const tokens = userDoc.get('tokens')
const notificationBody = (message['type'] === "TEXT") ? message['textMessage'] : "New message with Image"
const payload = {
notification: {
title: senderName + " sent you a message",
body: notificationBody,
clickAction: "ChatActivity" // возможно, это только для андроида
},
data: {
USER_NAME: senderName,
USER_ID: message['senderId']
}
}
return admin.messaging().sendToDevice(tokens, payload).then( response => {
const stillRegisteredTokens = tokens
response.results.forEach((result, index) => {
const error = result.error
if (error) {
const failedRegistrationToken = tokens[index]
console.error('failed token', failedRegistrationToken, error)
if (error.code === 'messaging/invalid-registration-token' || error.code == 'messaging/registration-token-not-registred') {
const failedIndex = stillRegisteredTokens.indexOf(failedRegistrationToken)
if (failedIndex > -1) {
stillRegisteredTokens.splice(failedIndex, 1)
}
}
}
})
return admin.firestore().doc("tokens" + recipientId).update({
tokens: stillRegisteredTokens
})
})
})
}
})
also i would ask about line "clickAction: "ChatActivity" it only for android? how can i do same to ios?
Thx a lot!
Try to delete the function from firebase console and redeploy
or
try changing Internet Service Provider and deploy

firebase Nodejs async cloud function not finishing execution

I am building a firebase cloud function that when I change a value in my db, I get UIDs of all users in db then check a node called wishlists to see if the user has products in one of his wishlists. if the wishlists of the users do not have products the cloud function sends a notification to the user with a msg to fill his wishlist. The function works for one user but when I iterate the user's nodes and call the work that I do for one user, it finishes before completing all the work. I believe that the probléme comes from not handling properly the async functions. Any help is appreciated. Thanks!
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const runtimeOpts = {
timeoutSeconds: 180,
memory: '1GB'
}
admin.initializeApp(functions.config().firebase);
exports.sendAdminNotificationForEmptyWishlists = functions.runWith(runtimeOpts)
.database.ref('/dev/fireNotifCloudFunc')
.onWrite(async () => {
// get all users uids
const ref = admin.database().ref().child('Influencers')
return ref.once("value")
.then(function(snapshot) {
snapshot.forEach( async function(child) {
await checkUserWishlists(child.key)
})
})
.catch(function(error){
console.log(error);
});
});
//check users wishlists
async function checkUserWishlists(uid){
var ref = admin.database().ref().child('Articles').child(uid)
ref.once("value")
.then(function(snapshot) {
if(snapshot.exists()){
const wishlistsNumber = snapshot.numChildren();
let wishlistCount = 0
let userHasProduct = false
var BreakException = {};
try {
snapshot.forEach(function(child) {
wishlistCount = wishlistCount + 1
//wishlist node
if(child.child("articles").exists()){
//user have not empty wishlist
userHasProduct = true
throw BreakException
}
});
}
catch(err){
if (err !== BreakException) throw err;
}
if((wishlistCount === wishlistsNumber) && !userHasProduct){
let fcmToken = (async () => {
fcmToken = await getUserFirestoreFCM(uid).then(()=>{
sendPushNotificationToUser(fcmToken,"emptyWishlists")
return fcmToken
})
.catch((error)=>{
console.log("error getting fcm token " + error);
})
})();
}
}
else{
console.log("user did not exist in articles node" );
return
}
})
.catch(function(error){
console.log(error);
});
}
async function getUserFirestoreFCM(uid){
let documentRef = admin.firestore().doc("users_table/" + uid);
documentRef.get().then(documentSnapshot => {
if (documentSnapshot.exists) {
console.log('Document exist')
return documentSnapshot.get('fcmToken')
}
else {
console.log('Document dosen\'t exist')
return
}
})
.catch(function(error){
console.log('error geting fcm token from firestore ' + error);
})
}
async function sendPushNotificationToUser(fcm,type){
//get fcm token
if(type === "emptyWishlists"){
//notification content
const payloadEmptyWishlists = {
notification: {
title: `Vos wishlists sont vides !`,
body: "Hello veuillez ajouter des produits dans vos wishlists pour joindre les
influenceurs dans le fil d'acceil, cheers ! ",
icon: "default",
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
//send notif
return admin.messaging().sendToDevice(fcm,
payloadEmptyWishlists,options).then(function(response){
console.log('Notification sent successfully:',response);
return
})
.catch(function(error){
console.log('Notification sent failed:',error);
});
}
}
this is a screeshot from the logs
I think you should not use async/await in forEach loop callaback. This generally is tricky. Searching for good explanation I have found this article. I think its very short and clear.
In this situation I don't think that you need this async/await, but I would have to implement it to be sure. Anyway, if it appear that you still need async there is workaround in mentioned article.

How to get json data from multiple url-pages Node.js?

I am quite new to Node.js and haven't been working with json data before so really hope that you can help me.
I am trying to get all event information from Ticketmaster's API and add specific variables to mongoDB. However, the APIs' that I am currently using are limited to 200 events per page. It is therefore not possible for me to connect the event information with venue information since these are added seperately to mongoDB and are not exhaustive of all event and venue information (not able to connect on ids because of missing event and venue data).
My question is therefore in regards to how I can get all pages into my database at once?
The code that I have written so far looks something like below:
app.get('/tm', (req, res) => {
axios // getting venues
.get('https://app.ticketmaster.com/discovery/v2/venues.json?apikey=myApiKey&page=0&size=200&countryCode=DK')
.then(response => {
const venuesToBeInserted = response.data._embedded.venues.map(venue => { // preparing venues
return {
sourceID: venue.id,
venue: venue.name,
postalCode: venue.postalCode,
city: venue.city.name,
country: venue.country.name,
countryCode: venue.country.countryCode,
address: !!venue.address ? venue.address.line1 : null,
longitude: !!venue.location ? venue.location.longitude : null,
latitude: !!venue.location ? venue.location.latitude : null,
source: 'ticketmaster'
}
})
// Create all venues at once
Venue.create(venuesToBeInserted).then(venues => {
console.log("venues inserted")
axios // getting events and shows - note the page parameter in the api link
.get('https://app.ticketmaster.com/discovery/v2/events.json?apikey=myApiKey&countryCode=DK&size=200&page=0')
.then(response => {
const eventsToBeInserted = response.data._embedded.events.map(events => { // preparing events
const event = events._embedded.attractions[0]
return {
sourceID: event.id,
name: event.name,
slug: slugify(event.name).toLowerCase(),
tags: !!event.classifications ? [event.classifications[0].genre.name, event.classifications[0].subGenre.nam] : [], // duplicate genres occur
// possible tags from ticketmaster: type and subtype
}
})
// Create all events at once
Event.create(eventsToBeInserted).then(events => {
console.log("events inserted")
const showsToBeInserted = response.data._embedded.events.map(show => {
const event = events.find(event => event.sourceID == show._embedded.attractions[0].id);
const venue = venues.find(venue => venue.sourceID == show._embedded.venues[0].id);
if (!!event && !!venue) {
return {
event: event._id,
venue: venue._id,
timezone: show.dates.timezone,
dateStart: !!show.dates.start.dateTime ? show.dates.start.dateTime : show.dates.start.localDate,
tickets: !!show.priceRanges ? {
minPrice: show.priceRanges[0].min,
maxPrice: show.priceRanges[0].max,
currency: show.priceRanges[0].currency
}: {}
}
}
})
// Let's see what we have created in the database
Venue.find({}).select({
name: 1,
slug: -1
}).limit(10).populate('event').populate('venue').then(events => {
console.log(util.inspect(events));
}).catch(err => {
console.error(err);
});
}).catch( err => {
console.error(err)
})
}).catch( err => {
console.error(err)
})
}).catch(err => {
console.error(err)
});
}).catch(err => {
console.error(err)
})
})
EDIT
Using the approach that Jake suggested gave me an error (Error: Requested failed with status code 401). I have tried to search for it online but I cannot figure out why the error happens.. See picture below of part of the error message in my console.log.
error message
You can do this using promises, which you already are using, you just need to chain them together using recursion.
function getVenues(page, size, venues) {
page = page || 0;
size = size || 200;
venues = venues || [];
return axios
.get(`https://app.ticketmaster.com/discovery/v2/venues.json?apikey=myApiKey&page=${page}&size=${size}&countryCode=DK`)
.then(response => response.data._embedded.venues)
.then(rawVenues => {
rawVenues.forEach(venue => venues.push(venue));
if (rawVenues.length < size) {
// All done return the compiled list.
return venues;
}
// Recurse over the next set of venues by adding another promise to the chain.
return getVenues(page + 1, size, venues);
});
}
function getEvents(page, size, events) {
page = page || 0;
size = size || 200;
events = events || [];
return axios
.get(`https://app.ticketmaster.com/discovery/v2/events.json?apikey=myApiKey&countryCode=DK&size=${size}&page=${page}`)
.then(response => response.data._embedded.events)
.then(rawEvents => {
rawEvents.forEach(event => events.push(event));
if (rawEvents.length < size) {
// All done return the compiled list.
return events;
}
// Recurse over the next set of events by adding another promise to the chain.
return getEvents(page + 1, size, events);
});
}
app.get('/tm', (req, res) => {
getVenues().then(rawVenues => {
const venuesToBeInserted = rawVenues.map(venue => {
return {
sourceID: venue.id,
venue: venue.name,
postalCode: venue.postalCode,
city: venue.city.name,
country: venue.country.name,
countryCode: venue.country.countryCode,
address: !!venue.address ? venue.address.line1 : null,
longitude: !!venue.location ? venue.location.longitude : null,
latitude: !!venue.location ? venue.location.latitude : null,
source: 'ticketmaster'
};
});
// Return promise so errors bubble up the chain...
return Venue.create(venuesToBeInserted).then(venues => {
console.log("venues inserted");
// Return promise so errors bubble up the chain...
return getEvents().then(rawEvents => {
const eventsToBeInserted = rawEvents.map(rawEvent => {
const event = events._embedded.attractions[0];
return {
sourceID: event.id,
name: event.name,
slug: slugify(event.name).toLowerCase(),
tags: !!event.classifications ? [event.classifications[0].genre.name, event.classifications[0].subGenre.nam] : []
};
});
// Return promise so errors bubble up the chain...
return Event.create(eventsToBeInserted).then(events => {
console.log("events inserted");
const showsToBeInserted = rawEvents.map(show => {
const event = events.find(event => event.sourceID == show._embedded.attractions[0].id);
const venue = venues.find(venue => venue.sourceID == show._embedded.venues[0].id);
if (!!event && !!venue) {
return {
event: event._id,
venue: venue._id,
timezone: show.dates.timezone,
dateStart: !!show.dates.start.dateTime ? show.dates.start.dateTime : show.dates.start.localDate,
tickets: !!show.priceRanges ? {
minPrice: show.priceRanges[0].min,
maxPrice: show.priceRanges[0].max,
currency: show.priceRanges[0].currency
} : {}
}
}
});
// Do something with the found shows...
});
});
});
}).then(() => { // This then is fired after all of the promises above have resolved...
return Venue.find({}).select({
name: 1,
slug: -1
}).limit(10).populate('event').populate('venue').then(events => {
console.log(util.inspect(events));
res.send(events);
});
}).catch(err => { // Catches any error during execution.
console.error(err);
res.status(500).send(err);
});;
});

Resources