firebase cloud function how to get value and update it - android

I'm trying to get a value from a place in my database add 1 to it and set it back but I'm getting different errors the latest is
TypeError: Cannot read property 'update' of undefined
at admin.database.ref.once.then (/user_code/lib/index.js:22:25)
not sure why its trying to read it as a property i thought it was a method? my entire method is this
admin.database().ref('users/' + senderId + '/contacts/' + recipientId)
.once('value').then((contactSnapshot) => {
var mContact = contactSnapshot.val()
let unread = mContact['unread']
console.log('contact name is ' + mContact['user_name'] + ' unread count is ' + unread)
unread++
var contactReference = mContact.ref
contactReference.update({'unread' : unread})
})
my console log prints fine with the contact name and the unread count I'm pretty useless at java script (this is actually type script) which i will be addressing any help appreciated

mContact = contactSnapshot.val() returns the raw javascript value of the location of the database that was queried. It contains no other reference objects. mContact will not have a ref property, unless you have a key value named ref in your database at that location.
It sounds like you want to contactSnapshot.ref instead. Or just the remember the reference as you originally constructed it:
const contactReference = admin.database().ref('users/' + senderId + '/contacts/' + recipientId)

Related

SQL search multiple values in same field

I have a list of id's to search.
I want to call all data matching the values in this list.
Matching data is returned as a list.
I tried to do this in a loop and using IN but it didn't work.
When I write the values in parentheses one by one, it gives results, but how can I give the data in the list as a parameter?
db.query(_tableName, where: "id IN ('0001','00002','00003')")
When I type in the form, the query takes place. Can I send the incoming array directly into parentheses, not one by one? For example,
db.query(_tableName, where: "id IN (_ids)")
Query method:
Future<List<ContentModel>> getDiscoverContent(List<String> _ids) async {
Database db = await instance.database;
var contents = await db.query(_tableName, where: "id IN ('')");
List<ContentModel> _recommendedList = contents.isNotEmpty
? contents.map((e) => ContentModel.fromMap(e)).toList()
: [];
return _recommendedList;
}
The simplest solution I found:
var contents = await db.query(_tableName,
where:
"id IN('${_ids[0]}','${_ids[1]}','${_ids[2]}','${_ids[3]}','${_ids[4]}',"
"'${_ids[5]}','${_ids[6]}','${_ids[7]}','${_ids[8]}','${_ids[9]}')");
If you have a different solution, feel free to tell me.
You may try like this. This worked for my use case.
List<int> _ids = [1, 2, 3, 4];
// Loop through the _ids list and append quotes to each id
// add the element into a new List called new_Ids
List<String> new_Ids = [];
for (var i = 0; i < _ids.length; i++) {
new_Ids.add("'" + _ids[i].toString() + "'");
}
// use join to make a string from the new list where ids are separated by comma
String ids_Str = new_Ids.join(',');
Use db.query and pass ids string in where itself. Other columns in where condition can be passed in whereArgs if you need.
var resultList = await db.query('your_table_name',
columns: ['id', 'column2'],
where: 'id IN ($ids_Str)');
OR use rawQuery
var resultList = await db.rawQuery("SELECT id, column2 FROM your_table_name WHERE id IN(" + ids_Str + ")");
You may need to be careful of SQL Injection as we are passing dynamic values. Not sure about the best practices here.

How to check if record exists or not using Anko?

I am learning to fetching data from sqlite using anko. I can print the data successfully (if the record exist) but my application always crash when the data doesn't exist.
the error says:
parseSingle accepts only cursors with a single entry
I know exactly the meaning of error, I just dont know how to solve it.
here is the code for query:
fun getUserByUid(uid: Int): UserModel
{
val data = context.database.use {
val db = context.database.readableDatabase
val columns = UserModel.COLUMN_ID + "," + UserModel.COLUMN_NAME + "," + UserModel.COLUMN_API_KEY
val query = db.select(UserModel.TABLE_NAME, columns)
.whereArgs("(uid = {userId})",
"userId" to uid)
query.exec {
val rowParser = classParser<UserModel>()
parseSingle(rowParser) // this line that trigger error exception
}
}
return data
}
I tried to find count function in query or rowParser variable to check if the record exist or not but could not find it.
From the wiki page.
https://github.com/Kotlin/anko/wiki/Anko-SQLite#parsing-query-results
Parsing query results
So we have some Cursor, and how can we parse it into regular classes? Anko provides functions parseSingle, parseOpt and parseList to do it much more easily.
Method Description
parseSingle(rowParser): T Parse exactly one row
parseOpt(rowParser): T? Parse zero or one row
parseList(rowParser): List Parse zero or more rows
Note that parseSingle() and parseOpt() will throw an exception if the received Cursor contains more than one row.

How to access Firebase Database node using contains() method?

I am working on an app using Firebase Database. In my Firebase Database I have a node like xxxxxx_yyyyyy, where xxxxxx represents first user ID and yyyyyy represents second user ID. Now I want to retrieve only nodes which contains xxxxxx_ from my database. I don't know how to do this. Because all I know is Firebase gives only equalsTo() method.
There is no query like contain(). I recommend to change node structure (locating yyyyy under xxxxx).
There Is no Query Like Contains in Fire base.!
if you dnt want to change structure of your node you can Store Data in list and then simply use list.contains() you will get your desired Result.!
HtBVbQP0qMSrCStroYsIiMSuhMC3 //node userID
Name:XXXXXXX
You can get this Data by using orderbychild(XXXXXX);
There is no contain() method, however, you can solve this problem in two ways:
Using the split() method from String class.
Using Regex Pattern
Here is the code:
String firebaseField = "xxxxxx_yyyyyy";
String[] data = firebaseField.split("_");
System.out.print("Using split method: ");
for(String part : data) {
if (part.equals("xxxxxx")) {
System.out.print(part + " ");
//Add your logic
}
}
Or
System.out.print("\nUsing Regex Pattern: ");
Pattern datePattern = Pattern.compile("_");
data = datePattern.split(firebaseField);
for(String part : data) {
if (part.equals("xxxxxx")) {
System.out.print(part + " ");
//Add your logic
}
}
Hope it helps.

request parameter in beforeSave() doesn't contain any stored values sent from android app

This is my android code :
ParseObject parseObject = new ParseObject("likes");
ParseObject parseuser=ParseObject.createWithoutData(ParseUser.class,post.getPosAuthorObjectId());
ParseObject parsepost=ParseObject.createWithoutData("posts",post.getObjectId());
parsepost.put("postAuthor",parseuser);
parseObject.put("ownerId", ParseObject.createWithoutData(ParseUser.class, ParseUser.getCurrentUser().getObjectId()));
parseObject.put("postId",parsepost);
parseObject.saveInBackground
I am trying to send some data regarding the user's id along with the post object so as to save the post object int the "likes" class and do changes in the post owner's attributes using masterkey without fetching the id of the post owner in a separate query as it is already stored in my android code .In my experimental beforeSave():
Parse.Cloud.beforeSave("likes",function(request,response){
var posts = Parse.Object.extend("posts");
var post=new posts();
var post=request.object.get("postId");
var user=Parse.Object.extend(Parse.User);
var user=new Parse.User();
var id =post.object.get("postAuthor").id;
if(id!=null){
response.success();
}
else{
response.error("The id is null");
}
});
Basically I am trying to retrieve the user id saved in the postobject and sent to the request parameter .But the output of my experiment is always null.
You're extending the Parse.Object for the user class and setting a new user using the same variable name. You can just get rid of the first var user line completely, since new Parse.User() works by default without any extending.
Anyway, try just console.log( request.object ); to see what you're actually passing in.

Sending and retrieving data from datastore with mobile backend starter

I'm trying to use Mobile Backend Starter in my Android application. In order to do that I need to store some data in the Datastore.
I'm using the provided object CloudEntity but I can only consistently insert and read String.
That's the example code I used to send data:
CloudEntity entity = new CloudEntity(TEST_KIND_NAME);
entity.put(KEY_DATE, new Date(System.currentTimeMillis()));
entity.put(KEY_CALENDAR, Calendar.getInstance());
entity.put(KEY_LONG, Long.valueOf(Long.MAX_VALUE));
entity.put(KEY_INTEGER, Integer.valueOf(Integer.MAX_VALUE));
getCloudBackend().insert(entity, simpleHandler);
and this is how I read the data back (next code goes in the onComplete in the CloudBackendHandler:
StringBuffer strBuff = new StringBuffer();
strBuff.append("Inserted: \n");
strBuff.append("\tId = " + result.getId() + "\n");
Object o;
o = result.get(KEY_DATE);
strBuff.append("\tDate was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_CALENDAR);
strBuff.append("\tCalendar was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_LONG);
strBuff.append("\tLong was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_INTEGER);
strBuff.append("\tInteger was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
o = result.get(KEY_BOOLEAN);
strBuff.append("\tBoolean was retrieved as : " + ((o == null)? "null" : o.getClass().getName()) + "\n");
mTvInfo.setText(strBuff);
And what I get as result is:
Data inserted as Date and Calendar returns null.
Data inserted as Integer returns BigDecimal.
Data inserted as Longreturns a String.
My question is: Can I send (and read back) other data than `String? And if so. How?
After some time experimenting with the Android Mobile Backed Starter I found a link to a "sort of" (very limited) documentation: Mobile Backend Starter.
What I found is that if you send an Integer (and if I trust de documentation a Float or a Double) it is stored in the DataStore as a numeric field. And is returned as a BigDecimal when you send a query (through ClouldQuery).
Nevertheless, if you pass a Long as a property in your CloudEntity, it will be stored as a String in the DataStore and returned as such. And this is not trivial, as String fields has limitations on allowed comparisons.
If you send a DateTime, the documentation tells you that you will get back a String, but don't tells you that it will be stored in the DataStore as a String too.
This is important because you can't do all the comparisons with Strings. It is only allowed the equality (and ne) comparison (you can't test a greater than filter over a String property in your queries). So you can't store timestamps as Long (will be converted to String and you won't be able to compare them) and you can't set timestamps as DateTime for the same reason. And you just can't store Date nor Calendar objects.
Anyway every CloudEntity has two DateTime porperties by default CloudEntity.PROP_CREATED_AT and CloudEntity.PROP_UPDATED_AT. You can set a query filter with this fields. To do so you need to set the filter as
CloudQuery myQuery = new CloudQuery(<your kind name>);
myQuery.set<things>...
DateTime dateTime = new DateTime(<the time you want>);
myQuery.setFilter(F.gt(CloudEntity.PROP_UPDATED_AT, dateTime));
You need to use a DateTime for the comparison. If you are courious, you can NOT use Date instead of DateTime for this comparation. You would get this error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code": 400,
"errors": [
{
"domain": "global",
"message": "java.lang.IllegalArgumentException: _updatedAt:java.util.LinkedHashMap is not a supported property type.",
"reason": "badRequest"
}
],
"message": "java.lang.IllegalArgumentException: _updatedAt: java.util.LinkedHashMap is not a supported property type."
...
Other weird thing is that, aparently, you can not do comparisons with dateTime = new DateTime(0) (i.e. 1970-01-01T01:00:00.000+01:00) as the backend receives the query as:
query: (_kindName:"Data") AND ( _updatedAt > "1970-01-01T01:00:00.000+01:00" ), schema: {_kindName=STRING, _updatedAt=STRING}
Won't give any error but will return nothing list: result: null. Looks like it treats the comparison as a String. If you use DateTime dateTime = new DateTime(1) instead, you will send a query as:
list: executing query: {filterDto={operator=GT, values=[_updatedAt, 1970-01-01T01:00:00.001+01:00]},
looks the same as before but the backend will execute the query as:
query: (_kindName:"Data") AND ( _updatedAt > 1 ), schema: {_kindName=STRING, _updatedAt=DOUBLE}
As I see a DOUBLE I tried submit a Double instead a DateTime, but it doesn't work (no error but not result).
But, GOOD NEWS EVERYONE! We can do the comparison with an Integer as:
Integer anInteger = Integer.valueOf(0);
myQuery.setFilter(F.gt(CloudEntity.PROP_UPDATED_AT, anInteger));
the backend sees:
query: (_kindName:"Data") AND ( _updatedAt > 0 ), schema: {_kindName=STRING, _updatedAt=INT32}
and we'll get the expected value (all the entities updated since 1970-01-01T01:00:00.000+01:00)
Sorry for my mistakes (my english isn't good) and I hope this can help someone and, at least, save him some time.

Categories

Resources