event.params.wildcard returning the wrong value - javascript

I have a pretty simple firebase function :
exports.sendFollowNotification = functions.database.ref('PendingRequest/{receiver_id}/{sender_id}').onWrite(requestEvent => {
const requestSnapShot = requestEvent.data;
const senderId = requestEvent.params.sender_id;
const targetId = requestEvent.params.receiver_id;
const target_token = requestSnapShot.child('sender').val();
const sender_token = requestSnapShot.child('receiver').val();
console.log('sender_id :'+senderId);
console.log('target_id :'+targetId);
console.log('target_token: '+ target_token);
console.log('sender_token: '+sender_token);
const pendingRequestPayload = {
data: {
token_sender : sender_token,
token_target : target_token,
request_sender : senderId,
request_receiver : targetId,
my_message_id: '0'
}
};
if(target_token != null){
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToDevice(target_token, pendingRequestPayload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
}
Whenever this function fires there are two values that gets swapped : senderId gets targetId value and vice versa. Both values are retrieved with the params property while nothing strange happens to the values i'm getting from requestSnapShot.child('value_name').val();
The dumb solution is just to swap the two values whenever i need them but well, that's a really dumb solution. What am I missing here ?

If "target" is "receiver", these are swapped:
const target_token = requestSnapShot.child('sender').val();
const sender_token = requestSnapShot.child('receiver').val();
Are you doing that intentionally to work around the problem?
Update:
It's hard to guess why this isn't working for you. I copied your code, eliminated your work-around, and shortened it for testing:
exports.sendFollowNotification = functions.database.ref('PendingRequest/{receiver_id}/{sender_id}')
.onWrite(requestEvent => {
const requestSnapShot = requestEvent.data;
const senderId = requestEvent.params.sender_id;
const targetId = requestEvent.params.receiver_id;
const target_token = requestSnapShot.child('receiver').val();
const sender_token = requestSnapShot.child('sender').val();
console.log('sender_id :'+senderId);
console.log('target_id :'+targetId);
console.log('target_token: '+ target_token);
console.log('sender_token: '+sender_token);
});
Ran with this data:
{
"PendingRequest" : {
"R1" : {
"S1" : {
"receiver" : "R-token",
"sender" : "S-token"
}
}
}
}
And got this log output:
sender_token: S-token
target_token: R-token
target_id :R1
sender_id :S1

Related

TypeError: snapshot.forEach is not a function - Loop through firebase database

I am struggling to understand why my function is failing when trying to loop through a snapshot from Firebase Realtime Database.
The function should read through each 'Topic', from within each 'Topic' there is an 'Articles' field which has approximately 10 articles associated with it. The function reads each article URL and scrapes the URL for the largest image on the article website.
It should then add a new field 'imageURL' to each 'Article'.
When deployed I receive the following:
TypeError: snapshot.forEach is not a function
scraper.js
exports.imageScraper = functions.database.ref("searchTrends/google")
.onUpdate((snapshot, context) => {
functions.logger.error(snapshot);
snapshot.forEach(function(trendSnapshot) {
// TrendSnapshot - Key is topic Num
// Value is topic details with list of articles
const topicNum = trendSnapshot.key;
trendSnapshot.forEach(function(innerChild) {
if (innerChild.key == "articles") {
innerChild.forEach(function(articleData) {
const articleNum = articleData.key;
const myUrl = articleData.child("url").val();
// console.log(myUrl);
const options = {
url: myUrl,
};
// console.log(options);
ogs(options, (error, results, response) => {
if (typeof results.ogImage === "undefined") {
console.log("no Image");
} else {
if (results.ogImage.url === undefined) {
return "done";
}
console.log(articleNum);
const DBRef = admin.database().ref("searchTrends/google/" +
topicNum + "/articles/" + articleNum);
DBRef.update({imageURL: results.ogImage.url});
}
});
});
return "done";
}
}).catch((error) => {
console.log("Transaction failed: ", error);
return null;
});
});
});
The error is telling you that snapshot does not have a method called forEach. It is a not a DataSnapshot object as you are expecting. It is a Change object, specifically Change<DataSnapshot> From the documentation:
For onWrite or onUpdate events, the first parameter is a Change object that contains two snapshots that represent the data state before and after the triggering event.
Also refer to the API documentation for onUpdate.

How to handle image upload with predefined error handling for form

I'm trying to include an optional image upload in my express app, but, with the way I've designed the app, I think it's trying to pass the image name from the body instead of using the separate function I've created for it. Is there any workaround for it to verify the file without digging into the models?
posts.post("/", async (req, res) => {
const postId = uuidv1();
const userId = req.query.userId;
let checkUser = await User.getById(userId);
if(checkUser.length === 0) {
User.create(userId);
}
const dateCreated = new Date().toLocaleString('en-GB');
const dateUpdated = dateCreated;
let bodyValues = [];
let invalid = false;
let picUpload;
if (req.files === undefined || req.files === null) {
picUpload = 'none';
} else {
picUpload = req.files.image;
picUpload.mv('./images' + picUpload.name);
}
Post.fillable_properties.map(function (v) {
if (req.body[v] === null || req.body[v] === undefined)
invalid = true;
else bodyValues.push(req.body[v]);
});
bodyValues = [postId, ...bodyValues, picUpload, userId, dateUpdated, dateCreated];
if (!invalid) {
const [results, error] = await Post.create(bodyValues);
if (error.length == 0 && results.affectedRows == 1)
res.status(201).json(response.prepare(201, results, error));
else
res.status(400).json(response.prepare(400, results, error));
} else {
res.status(400).json(response.prepare(400, [], [{ "message": "Missing data" }, bodyValues]));
}
});
It sets invalid as true probably because the image is not part of the request body, but I don't know how to handle that.
Ultimately I worked around it within the client to set the file name to an empty string if there's no image to be uploaded, while not ideal it solves the issue in the meantime.

Not getting to function on GET

Behavior I'm getting from the code shown in the attached print screen: my FOR loop executes and then the two 'LET' (i.e. let path_get... and let get = https.get...).
Problem: when the 2nd LET is executed, the code goes back to the FOR, without ever executing the function storeCarData.
My intention: every time that the second LET executes (GET call), I want storeCarData to to be executed taking as inputs the result of this GET. This is probably an async/await question but I need your help in pointing out where to insert the asyncs/awaits if possible. I need to execute ALL of the functions in sequence (i.e one executes only after the previous one has returned).
Could you please help me here? In summary: when I execute the GET I want storeCarData to run, using the GET outputs as inputs for the function.
Thank you in advance.
Diego
PS: full code below
const https = require('https');
const url = require('url');
exports.handler = (req, res) => {
var page_number = (typeof(req.body.state) == 'undefined' || typeof(req.body.state.page_number) == 'undefined') ? 1 : req.body.state.page_number+1;
var kbb_vehicles = [];
var price_type = [2,3];
var price_description = ['C2C','C2B'];
// PRICE TYPES
// "ID": 1, "Typical Dealer Asking Price"
// "ID": 2, Private Party Value (for owners)"
// "ID": 3, "Trade-In Value"
// "ID": 4, "Private Party Value (for shoppers)"
var epoch = new Date().getTime();
console.log(`Date time is ${epoch}`);
var path_get_all_vehicles = `/Gps/GetAllVehicle?securityToken=${req.body.secrets.securityToken}&language=pt-BR&withCount=true&pageNumber=${page_number}&records=100`;
// GET ALL CARS
let get = https.get(
{
hostname: 'api.kbb.com.br',
path: path_get_all_vehicles
},
(getRes) => {
var reply = "";
getRes.on("data", (chunk) => {
(reply += chunk);
}
);
getRes.on("end", () => {
var obj = "";
var obj = JSON.parse(reply);
gotCars(obj.Response.VehicleList);
}
);
}
);
function gotCars(carsJustObtained) {
// PASS ALL CARS
for (var car of carsJustObtained) {
// NOW FOR A GIVEN CAR...
for (var i=0; i<=1; i++){
// ...GET PRICES TYPES 2 AND 3
let path_get_all_prices = `/Gps/GetAllVehiclePrices?vehicleID=${car.ID}&securityToken=${req.body.secrets.securityToken}&vehiclePriceTypeID=${price_type[i]}`;
// console.log(`path_get_all_prices is ${path_get_all_prices}`);
// console.log(`i is ${i}`);
// console.log(`price_type[i] is ${price_type[i]}`);
let get = https.get(
{
hostname: 'api.kbb.com.br',
path: path_get_all_prices
},
(getRes) => {
var reply = "";
getRes.on("data", (chunk) => {
(reply += chunk);
}
);
getRes.on("end", () => {
var obj = "";
var obj = JSON.parse(reply);
// WRITE PRICES INTO OBJECT >> APPEND RESULTS
var grades_array = obj.Response;
storeCarData(car, grades_array,i);
});
}
);
// price_description[0] is equal to C2C
// price_description[1] is equal to C2B
// grades_array[0] corresponds to VehicleGrade=2, thus "Fair"
// grades_array[1] corresponds to VehicleGrade=3, thus "Good"
// grades_array[2] corresponds to VehicleGrade=2, thus "Excellent"
function storeCarData(car, grades_array,i){
var carData = {
timestamp: epoch,
ID : car.ID,
BrandID : car.BrandID,
ModelID : car.ModelID,
VersionID : car.VersionID,
BrandName : car.BrandName,
ModelName : car.ModelName,
VersionName : car.VersionName,
Year : car.Year,
MSRP : car.MSRP,
ISV : car.ISV,
TransportCost : car.TransportCost,
AdminCost : car.AdminCost,
RoadTax : car.RoadTax,
StartYearImported : car.StartYearImported,
EndYearImported : car.EndYearImported,
BodyTypeID : car.BodyTypeID,
CC : car.CC,
HP : car.HP,
KW : car.KW,
Torque : car.Torque,
NrCilinders : car.NrCilinders,
TransmissionTypeID : car.TransmissionTypeID,
Gears : car.Gears,
NrDoors : car.NrDoors,
NrSeats : car.NrSeats,
FuelTypeID : car.FuelTypeID,
EngineTypeID : car.EngineTypeID,
ExhaustTypeID : car.ExhaustTypeID,
DistanceAxis : car.DistanceAxis,
Volume : car.Volume,
DriveTrainID : car.DriveTrainID,
Weight : car.Weight,
WeightCarriage : car.WeightCarriage,
VehicleTypeID : car.VehicleTypeID,
VehicleCilindersID : car.VehicleCilindersID,
FirstMediaURL : car.FirstMediaURL,
CombinedConsumption : car.CombinedConsumption,
UrbanConsumption : car.UrbanConsumption,
ExtraUrbanConsumption : car.ExtraUrbanConsumption,
MaximumSpeed : car.MaximumSpeed,
FuelTankRangeKM : car.FuelTankRangeKM,
FuelTankCapacity : car.FuelTankCapacity,
Acceleration0to100 : car.Acceleration0to100,
EmissionsCO2 : car.EmissionsCO2,
FirstMktCategoryID : car.FirstMktCategoryID,
PriceType : car.PriceType,
Grade : car.Grade,
TAMileage : car.TAMileage,
TAAge : car.TAAge,
AVMileage : car.AVMileage,
AuctionPrice : car.AuctionPrice,
AskingPrice : car.AskingPrice,
TradeInPrice : car.TradeInPrice,
PrivatePartyPrice : car.PrivatePartyPrice,
C2CPrice : car.C2CPrice,
VersionCatalogID : car.VersionCatalogID,
ExternalReference : car.ExternalReference,
VehicleSeriesName : car.VehicleSeriesName,
VehicleVersionNameLong : car.VehicleVersionNameLong,
FirstMediaCompleteURLLarge : car.FirstMediaCompleteURLLarge,
FirstMediaCompleteURLMedium : car.FirstMediaCompleteURLMedium,
FirstMediaCompleteURLSmall : car.FirstMediaCompleteURLSmall,
BedLength : car.BedLength,
CabType : car.CabType,
}
storePrices(grades_array,carData.timestamp, carData.ID, price_description[i]);
};
function storePrices(grades_array, timestamp, carID, price_description){
var prices = {
timestamp:timestamp,
carID:carID,
[`PriceFPP_FairCondition_${price_description}`]: grades_array[0].VehiclePrices.FPP,
[`PriceFPP_GoodCondition_${price_description}`]: grades_array[1].VehiclePrices.FPP,
[`PriceFPP_ExcellentCondition_${price_description}`]: grades_array[2].VehiclePrices.FPP,
[`PriceLow_FairCondition_${price_description}`]: grades_array[0].VehiclePrices.PriceLow,
[`PriceLow_GoodCondition_${price_description}`]: grades_array[1].VehiclePrices.PriceLow,
[`PriceLow_ExcellentCondition_${price_description}`]: grades_array[2].VehiclePrices.PriceLow,
[`PriceHigh_FairCondition_${price_description}`]: grades_array[0].VehiclePrices.PriceHigh,
[`PriceHigh_GoodCondition_${price_description}`]: grades_array[1].VehiclePrices.PriceHigh,
[`PriceHigh_ExcellentCondition_${price_description}`]: grades_array[2].VehiclePrices.PriceHigh,
[`EquipmentAdjustedPrice_FairCondition_${price_description}`]: grades_array[0].VehiclePrices.EquipmentAdjustedPrice,
[`EquipmentAdjustedPrice_GoodCondition_${price_description}`]: grades_array[1].VehiclePrices.EquipmentAdjustedPrice,
[`EquipmentAdjustedPrice_ExcellentCondition_${price_description}`]: grades_array[2].VehiclePrices.EquipmentAdjustedPrice,
[`BaseDiscountedPrice_FairCondition_${price_description}`]: grades_array[0].VehiclePrices.BaseDiscountedPrice,
[`BaseDiscountedPrice_GoodCondition_${price_description}`]: grades_array[1].VehiclePrices.BaseDiscountedPrice,
[`BaseDiscountedPrice_ExcellentCondition_${price_description}`]: grades_array[2].VehiclePrices.BaseDiscountedPrice
}
};
};
};
};
}
Almost any time that you see a call to some .on(...), that code isn’t going to run right away, but at some future time.
To make this async, you can wrap the whole thing in a Promise() constructor, and then call resolve() when the thing that you were waiting for has actually happened.
The minimal change to your code for that would be:
let get = new Promise(resolve => {
https.get(
{
hostname: "api.kbb.com.br",
path: path_get_all_vehicles,
},
(getRes) => {
var reply = "";
getRes.on("data", (chunk) => {
reply += chunk;
});
getRes.on("end", () => {
var obj = "";
var obj = JSON.parse(reply);
gotCars(obj.Response.VehicleList);
resolve();
});
}
);
});
Now if you console.log() the value of get, you’ll see that it’s a Promise object. The for loop will still keep running, but now that you have a promise, you can await get on the next line. To be able to use that syntax though, you’ll have to make the containing function async, that is, change (req, res) => … to async (req, res) => ….
Some additional things to worry about later, once you get the basics working:
What if the http request fails? Then you’ll want to throw an exception or something. Look up Promise.reject() for that case.
Now that the request handler is async, express’s default error-handling stuff won’t work so well. This package might help though I personally haven’t used it.
Those are other issues for other times, but hopefully this helps you get unstuck.

why object variable property did not work in nodejs

I have a utility function which pass parameters 'name page callback' to the function. Why not work as i tried so many times?
PLUS: seems 'query.tag_id = name' work for me but why query[name] = name did not work so that i can pass whatever name i like;That's, i want to pass the variable /name/ as the property name so that i can use whatever name i like. For example, i can find posts by user_id when i pass user_id variable as the name value. Also i can find posts by its tag_id when i pass tag_id variable as the name value so it's much more flexible than when i use 'query.user_id = name' to do it ,where the name can only be user_id variable or value
NO LIBRARY USED EXCEPT EXPRESS AND NODEJS WITH CONNECT-FLESH, MONGOOSE ETC.
// post_proxy/post.js
"use strict";
let moment = require('moment'),
Post = require('../models/Post'),
User = require('../models/User'),
Comment = require('../models/Comment'),
postProxy = require('../db_proxy/post'),
tagProxy = require('../db_proxy/tag');
module.exports = {
getTen: (name,page,callback)=>{
var query = {};
//name = query;
if(name){
query[name] = name;
console.log('query[name] is'+ Object.keys(query));
}
Post.count(query, ( err, count)=>{
if (err) {
return callback(err);
}else{
console.log( `Number of posts: ${count} . query is ${query}` );
Post.find(query).skip((page-1)*10).limit(10).sort({created_at: -1}).exec((err,posts)=>{
if (err) {
return callback(err);
}
console.log('Posts inthe getTen function is: '+posts);
const modifiedPosts = posts.map(post=>{
return post.processPost(post);
});
console.log('modifiedPosts: '+modifiedPosts);
callback(null, modifiedPosts, count);//provide the params(caluated values),and what to do? you need to figure it out yourself
});
}
});
}
// controller/post.js:
"use strict";
let moment = require('moment'),
Post = require('../models/Post'),
User = require('../models/User'),
Comment = require('../models/Comment'),
postProxy = require('../db_proxy/post'),
tagProxy = require('../db_proxy/tag');
module.exports = {
getTagsPost: (req,res)=>{
const tag_id = req.params.tag_id;
const page = req.query.p ? parseInt(req.query.p) : 1;
//let loginedUser;
console.log('entering into the tagpost');
postProxy.getTen(tag_id, page, (err, posts, count)=> {
if (err) {
console.log('some error with getting the 10 posts:'+ err);
//next(err);
posts = [];
}
// if(req.user){
// loginedUser = req.user.processUser(req.user);
// }
//userProxy.getUserById(user_id, theuser=>{
console.log('tag posts for'+ tag_id +posts);
res.render('post/tagPosts', {
title: 'specific tag page',
user: req.user ? req.user.processUser(req.user) : req.user,
//postUser: req.user ? (req.user._id == user_id ? loginedUser : theuser) : theuser,
posts: posts,
page: page,
isFirstPage: (page - 1) == 0,
isLastPage: ((page - 1) * 10 + posts.length) == count,
messages: {
error: req.flash('error'),
success: req.flash('success'),
info: req.flash('info'),
}, // get the user out of session and pass to template
});
});
},
...
}
//route:
router.get('/tag/:tag_id', post.getTagsPost);
UPDATE:
Did not find an answer so i change it to the following and solve the problems:
getTen: (name,tag_id,user_id,page,callback)=>{
var query = {};
if(name){
if(user_id){
query.user_id = name;
}else{
query.tag_id = name;
}
console.log('query[name] is'+ Object.keys(query));
}
...
}
UPDATE: Did not find an answer so i change it to the following and solve the problems:
getTen: (name,tag_id,user_id,page,callback)=>{
var query = {};
if(name){
if(user_id){
query.user_id = name;
}else{
query.tag_id = name;
}
console.log('query[name] is'+ Object.keys(query));
}
...
}

Firebase custom query

How to get the value of Inmate_DOB from the below structure of Firebase Web API.
Please find the snap below :
I tried the below code is it right to handle, But I didn't retrieve the value.
GetInmate.Js
angular.module('starter.InMateIdContactDetailsController', ['firebase'])
.controller('InMateIdContactDetailsCtrl', function($scope,$rootScope,$filter,$ionicLoading,$state,$window, $cordovaSQLite,$cordovaCamera,$firebase,$firebaseAuth,$firebaseArray) {
var userId = firebase.auth().currentUser.uid;
var ref = firebase.database().ref().child("Tables/Inmate_Data");
$scope.InMatedata = $firebaseArray(ref);
if(!$scope.InMatedata){
alert('Records not found Auth!');
}else{
alert('Records found! Auth');
}
firebase.auth().onAuthStateChanged(function(user) {
if(user) {
var userID = user.uid;
firebase.database().ref('Tables/Inmate_Data/'+userID).once('value').then(snapshot => {
const userDOB = snapshot.val().Inmate_DOB;
alert(userDOB);
alert(test);
})
}
});
});
I think you are just missing a / in your original code after 'Tables/Inmate_Data'.
return firebase.database().ref('Tables/Inmate_Data/' + userId).once('value')
.then(function(snapshot) {
var Inmate_dob = snapshot.val().Inmate_DOB;
alert(Inmate_dob);
}
Instead of using firebase.auth().currentUser.uid, you might want to use onAuthStateChanged(), this way you can always be sure that the code inside the block will only be executed if the user is actually logged in otherwise firebase.auth().currentUser might return null. If you have made sure that this value is not null, then you can do something like this:
var userID = firebase.auth().currentUser.uid; //Current User UID
firebase.database().ref('Tables/Inmate_Data/'+userID).once('value').then(snapshot => {
const userDOB = snapshot.val().Inmate_DOB;
alert(userDOB);
});
To avoid getting null, you can put the above code inside onAuthStateChanged
firebase.auth().onAuthStateChanged(function(user) {
if(user) {
var userID = user.uid;
firebase.database().ref('Tables/Inmate_Data/'+userID).once('value').then(snapshot => {
const userDOB = snapshot.val().Inmate_DOB;
alert(userDOB);
});
}
});
If you want to retrieve the date of birth of all users, then you can do something like this:
firebase.database().ref('Tables/Inmate_Data').on('child_added', snapshot => {
firebase.database().ref(snapshot.key+'/Inmate_DOB').on('value', snap => {
const userDOB = snap.val();
alert(userDOB);
});
});

Categories