Node JS and Firebase Unable to Search Using equal.To() - node.js

I've started reading into creating Google Actions using Node.JS/Dialogflow/Firebase.
I have reached a big stumbling block, in trying to get a simple code running that would search a Firebase database for a certain value and then report back. For example from the JSON output, I would like to search for the applicationID and have the age passed back as the output.
I would be extremely grateful if someone can review my code and direct me in the right direction.
Table Structure
{
"groupA" : {
"applications" : {
"100" : {
"age" : 20,
"result" : "pass"
},
"200" : {
"age" : 25,
" result " : "pass"
},
"500" : {
"age" : 20,
" result " : "fail"
}
}
}
}
Node JS
return admin.database().ref('groupA').child('applications').orderByChild('applications').equalTo(500)
.once('value')
.then(acceptedApplicationsSnapshot => {
var id = acceptedApplicationsSnapshot.val().age;
var data = acceptedApplicationsSnapshot.val();
var theAge = acceptedApplicationsSnapshot.child("age").val();
agent.add('some random text' + theAge);
});
Within this example the value 500 should be searched with the age then given as the output.

You're ordering/filtering on property applications, but the value you're passing in is a key. So you'll want to use orderByKey instead of orderByChild:
return admin.database().ref('groupA').child('applications').orderByKey().equalTo(500)
A query may match multiple child nodes, so the above returns a snapshot with a list of results. Even when there's only one result, the query will return a list of one result:
{
"500": {
"age" : 20,
" result " : "fail"
}
}
This means that you'll need to loop over the results in your callback:
acceptedApplicationsSnapshot.forEach(appSnapshot => {
var theAge = appSnapshot.child("age").val();
agent.add('some random text' + theAge)
})
Since you know the exact key of the child node you want, you can also simply keep using child() to access the specific node:
return admin.database().ref('groupA').child('applications').child('500')
This will result in a snapshot of that specific node being returned, instead of the list-with-a-single-child-node of the previous snippet.
{
"age" : 20,
" result " : "fail"
}
And then you can use your existing code to retrieve the age from the snapshot.

To search for the applicationsID=500 and have the age passed back as the output, you can try this.
var db = admin.database();
var ref = db.ref("groupA").child("applications/500").once('value')
.then(function(dataSnapshot){
console.log(dataSnapshot.val().age);
});
More info here.
Edited: This should give you the age, in this case equals 20, for the parameter you pass in applications/500 in the code above.
Let me know if it helps.

Related

NodeJS Iterate through City in JSON, Return Cities and Users in each City

I have the below snippet from a JSON Object that has 3,500 records in it.
[
{
"use:firstName": "Bob",
"use:lastName": "Smith",
"use:categoryId": 36,
"use:company": "BobSmith",
"use:webExId": "Bob.Smith#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-TX",
"com:country": 1
}
},
{
"use:firstName": "Jane",
"use:lastName": "Doe",
"use:categoryId": 36,
"use:webExId": "Jane.Doe#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-CA",
"com:country": "1_1"
}
}
{
"use:firstName": "Sam",
"use:lastName": "Sneed",
"use:categoryId": 36,
"use:webExId": "Sam.Sneed#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-CA",
"com:country": "1_1"
}
}
]
I am using NodeJS and I have been stuck on figuring out the best way to:
1. Iterate through ['use:address']['com:city' to map out and identify all of the Cities. (In the example above, I have two: US-TX and US-CA in the three records provided)
2. Then identify how many records match each City (In the example above, I would have US-TX: 1 and US-CA: 2)
The only code I have is the easy part which is doing a forEach loop through the JSON data, defining userCity variable (to make it easier for me) and then logging to console the results (which is really unnecessary but I did it to confirm I was looping through JSON properly).
function test() {
const webexSiteUserListJson = fs.readFileSync('./src/db/webexSiteUserDetail.json');
const webexSiteUsers = JSON.parse(webexSiteUserListJson);
webexSiteUsers.forEach((userDetails) => {
let userCity = userDetails['use:address']['com:city'];
console.log(userCity);
})
};
I've been searching endlessly for help on the topic and probably not formulating my question properly. Any suggestions are appreciated on how to:
1. Iterate through ['use:address']['com:city' to map out and identify all of the Cities.
2. Then identify how many records match each City (In the example above, I would have US-TX: 1 and US-CA: 2)
Thank you!
You could reduce the webexSiteUsers array into an object that is keyed by city, where each value is the number of times the city occurs. Something like the below should work.
const counts = webexSiteUsers.reduce((countMemo, userDetails) => {
let userCity = userDetails['use:address']['com:city'];
if (countMemo[userCity]) {
countMemo[userCity] = countMemo[userCity] + 1;
} else {
countMemo[userCity] = 1;
}
return countMemo;
}, {});
counts will then be an object that looks like this.
{
"US-TX": 1,
"US-CA": 2
}

How to add a number to a DynamoDB number set using Node.js

I'm just trying to add a number to a number set in DynamoDB. This expression was working with an untyped list. But to save space since it will just be storing numbers I moved everything to plain number sets. Now no matter how much I tinker with it I can't get it to go through.
var phoneID = req.body.PhoneID;
var category = req.body.ratingCategory;
var ratingToAdd = [Number(req.body.rating)]
var dbparams = {
"TableName": "Venue_Ratings",
Key: {
"PhoneID" : phoneID
},
"UpdateExpression": "SET #categoryName = list_append(#categoryName, :rating)",
"ExpressionAttributeNames" : {
"#categoryName" : category
},
"ExpressionAttributeValues": {
":rating": ratingToAdd
},
"ReturnValues": "ALL_NEW"
};
This error is being thrown An operand in the update expression has an incorrect data type
I have also tried changing the update expression to an ADD expression instead like so ADD #categoryName :rating.
I've tried changing ratingToAdd to a plain number not in an array, a string in an array, and a plain string not in an array.
I'm calling the db using the docClient.update method.
I have verified that the sets in the db are in fact number sets and that they exist.
What am I missing here? Thanks for the help.
The below code should add the number to the Number Set (i.e. DynamoDB data type 'NS').
Use this function with ADD in UpdateExpression:-
docClient.createSet([Number(5)])
Code:-
var params = {
TableName : "Movies",
Key : {
"yearkey" : 2016,
"title" : "The Big New Movie 1"
},
UpdateExpression : "ADD #category :categorySet",
ExpressionAttributeNames: {
'#category' : 'category'
},
ExpressionAttributeValues: {':categorySet' : docClient.createSet( [Number(5)])},
ReturnValues: 'UPDATED_NEW'
};

Getting error "pipeline element 3 is not an object error", while trying to find & update using aggregate

I am using node js mongodb driver & trying to update an object array inside an object array in a document.
The schema of the document collection is this :
What I Want :
For collection with order no = 1 & items.qty=2 & tax rate = 25, update the tax to "cst" & taxratetype to "flat".
What I Tried :
db.OrderInfo.aggregate(
{$match:{"orderno":"1"}},
{$unwind:'$items'},
{ $match: { 'items.qty' : 2}
},function(err,result1){
if(err){
throw(err);
}else{
indexes = result1[0].items.taxes.map(function(obj, index) {
if(obj.taxrate == 25) {
return index;
}
}).filter(isFinite);
var updateData = {};
updateData["items.$.taxes."+indexes[0]+".tax"]="cst";
updateData["items.$.taxes."+indexes[0]+".taxratetype"]="flat";
db.OrderInfo.update({ "orderno":"1",'items.qty': 2,'items.taxes.taxrate': 25 },{$set: updateData },function(err,result2){
console.log(result2);
});
}
});
Currently I am using db.eval to run this script from node but later will change it once I accomplish the same.
Getting this Error :
{"name":"MongoError","message":"Error: command failed: {\n\t\"ok\" :
0,\n\t\"errmsg\" : \"pipeline element 3 is not an
object\",\n\t\"code\" : 15942\n} : aggregate failed
:\n_getErrorWithCode#src/mongo/shell/utils.js:25:13\ndoassert#src/mongo/shell/assert.js:13:14\nassert.commandWorked#src/mongo/shell/assert.js:267:5\nDBCollection.prototype.aggregate#src/mongo/shell/collection.js:1312:5\n_funcs1#:1:31\n","ok":0,"errmsg":"Error:
command failed: {\n\t\"ok\" : 0,\n\t\"errmsg\" : \"pipeline element 3
is not an object\",\n\t\"code\" : 15942\n} : aggregate failed
:\n_getErrorWithCode#src/mongo/shell/utils.js:25:13\ndoassert#src/mongo/shell/assert.js:13:14\nassert.commandWorked#src/mongo/shell/assert.js:267:5\nDBCollection.prototype.aggregate#src/mongo/shell/collection.js:1312:5\n_funcs1#:1:31\n","code":139}
I know from this issue https://jira.mongodb.org/browse/SERVER-831
that I cannot use a direct update command & hence trying this workaround.
Any other approach for such updates is also fine with me.
EDIT :
As per answer given by #titi23, I had tried using [] also inside function.
It did not gave me any error but, my values also did not get updated.
Two problems in the query :
1) You are missing [] in the aggregate query.
2) The update method does not need the tax rate clause. It will find the nested document & the index from aggregate would serve the purpose in update.
Refer aggregate-definition for more info on how to use it.
Syntax - db.collection.aggregate(pipeline, options)
pipeline - array - A sequence of data aggregation operations or stages.
Try the following:-
db.OrderInfo.aggregate([
{$match:{"orderno":"1"}},
{$unwind:'$items'},
{ $match: { 'items.qty' : 2} }]).toArray(
function(err,result1){
if(err){
throw(err);
}
else{
console.log(result[0]); //See is there any record here
indexes = result1[0].items.taxes.map(function(obj, index) {
if(obj.taxrate == 25) {
return index;
}
}).filter(isFinite);
var updateData = {};
updateData["items.$.taxes."+indexes[0]+".tax"]="cst";
updateData["items.$.taxes."+indexes[0]+".taxratetype"]="flat";
db.OrderInfo.update({ "orderno":"1",'items.qty': 2}, /*Remove the tax rate clause from here..*/
{$set: updateData },function(err,result2){
console.log(result2);
});
}
});
It should not throw the error.
EDIT:- Do toArray() with the aggregate, see if it helps. Updated the query already.

Passing variables into a query in mongoose in the first argument

I am using MEAN stack, i have an entry like this in my mongodb
{ "_id" : ObjectId("5577467683f4716018db19ed"),
"requestMatrix" : { "1698005072" : { "rideId" : "641719948", "status" :"accepted" },"1698005073" : { "rideId" : "641719545", "status" :"rejected" } },
"partners":[ { "customerNumber" : 1698005072 }, { "customerNumber" : 1698072688 } ]}
I want to query the db to return me this entire document based on whether the status is accepted or rejected.
When I run the below query in a command prompt, i get the expected answer
db.joinedrides.find({'requestMatrix.1698005072.status':"accepted"})
But when i want to do the same from nodeJs, I am stuck as the number 1698005072 in the above query is a variable, i am not able to write a query for that.
tried something like this
var criteria = "'requestMatrix.'"+customerNumber+"'.status'";
JoinedRide.find({criteria:"accepted"},function(err,joinedRides){
})
where customerNumber will vary for different requests, in the above mentioned case its value is 1698005072
Any help is appreciated.
You need to do something like this:
var query = {};
var criteria = "requestMatrix." + customerNumber + ".status";
query[criteria] = "accepted"
JoinedRide.find(query,function(err,joinedRides){
})

MongoDB full text search on string array

So I'm using Node.js with MongoDB for my web application. I'm having some trouble creating a text index for my schema and searching for text within an array. I've looked at the mongo docs but haven't found anything related to this specifically.
My current implementation searches successfully on regular String values, but querying for text matching in [String]'s don't return anything.
Here's my REST call:
...console.log("Query string: " + str);
var qry = {
"$text": {
"$search": str
}
};
model.find(qry, function (err, results) {...
And when I create my schema:
var blah = new Schema({
foo : String,
bar : [String],
...
blah.index({
foo: 'text',
bar: 'text'
});
Any query won't return the results that match in bar. A query string for something within foo works fine.
Double check that you've created the correct indexes on the correct collections and the queries are being issued to the correct collections. Indexing an array works for me:
> db.test.drop()
> db.test.insert({ "_id" : 0, "a" : "dogs are good" })
> db.test.insert({ "_id" : 1, "a" : "I like dogs", "b" : ["where's my dog?", "here, have a cat"] })
> db.test.insert({ "_id" : 2, "b" : ["she borrowed my dog", "my frogs are croaking"] })
> db.test.ensureIndex({ "a" : "text", "b" : "text" })
> db.test.find({ "$text" : { "$search" : "dogs" } }, { "_id" : 1 })
{ "_id" : 0 }
{ "_id" : 2 }
{ "_id" : 1 }
Okay, I finally figured it out! Turns out, grunt serve doesn't update indexes in the database. I had created a text index for "foo" only and that didn't update when I added "bar" to the index. I had to run - in mongo shell:
db.dropDatabase()
The next time I ran it, the database was recreated and the proper indexes were set. If anyone else runs across this issue, try running db.getIndexes().

Resources