Parse.com: query on an array field not working with a big number of values - arrays

I use Parse.com Core and Cloud Code to store data and perform some operations for a mobile app. I have an issue with a query on an array field that is sometimes not returning anything even if I am sure it should.
I store a large amount of phone numbers in an array field to keep track of user's matching contacts.
This field is called phoneContacts and look like this (with numbers only, this is just as an example):
["+33W30VXXX0V","+33W30VXX843","+33W30VZVZVZ","+33W34W3X0Y4","+33W34W386Y0", ...]
I have a function in Cloud Code that is supposed to get matching rows for a given phone number. Here is my query:
var phoneNumber = request.params.phoneNumber;
var queryPhone = new Parse.Query('UserData');
queryPhone.equalTo('phoneContacts', phoneNumber); // phoneNumber is passed as a string param, i.e. "+33W30VXX843"
queryPhone.include('user');
var usersToNotify = [];
return queryPhone.each(function(userData) {
var user = userData.get('user');
usersToNotify.push(user.get('username'));
})
.then(function() {
return usersToNotify;
});
I tested my query with an array of 2 or 3 phone numbers and it works well and returns the expected rows. But then I tried with a user having around 300 phone numbers in that phoneContacts field and even if I query a value that is present (appear with a filter in Parse Data Browser), nothing is returned. To be sure I even took a phone number existing in 2 rows: one with few values and one with many, and only the row with a few values got returned.
I've read carefully the Parse documentation and especially about queries and field limits, but it doesn't seem to have a restriction on the number of values for an array field, and nothing says that query might not work with a lot of values.
Anybody can point me in the right direction? Should I design my Parse Classes differently to avoid having so many values in an array field? Or is there something wrong with the query?

You need to be using a PFRelation or some sort of intermediate table. You should not use an array to store 300 phone numbers, your queries will get really slow.
PFRelations:
https://parse.com/docs/osx/api/Classes/PFRelation.html
http://blog.parse.com/learn/engineering/new-many-to-many/

Related

ImportJSON for Google Sheets Can't Handle File WIthout Properties?

I'm trying to pull historical pricing data from CoinGecko's free API to use in a Google Sheet. It presents OHLC numbers in the following format:
[
[1589155200000,0.05129,0.05129,0.047632,0.047632],
[1589500800000,0.047784,0.052329,0.047784,0.052329],
[1589846400000,0.049656,0.053302,0.049656,0.053302],
...
]
As you can see, this isn't typical JSON format since there are no property names. So that everyone is on the same page, for this data the properties of each subarray in order are Time (in UNIX epoch format), Open Price, High Price, Low Price, and Close Price.
I'm using the ImportJSON code found here to try and pull this data, but it does not work. Instead of putting each subarray into a separate row, split into columns for the 5 properties, it prints everything out into a single cell like so:
1589155200000,0.05129,0.05129,0.047632,0.047632,1589500800000,0.047784,0.052329,0.047784,0.052329,15898 6400000,0.049656,0.053302,0.049656,0.053302,...
This is incredibly unhelpful. I'm trying to avoid using a paid API add-on since I really don't want to have to pay the frankly exorbitant fees they want to charge, but I can't figure out a way to get ImportJSON to play nicely with this data. Does anyone know of a solution?
It's simplier : your datas are in an array structure : I put
[
[1589155200000,0.05129,0.05129,0.047632,0.047632],
[1589500800000,0.047784,0.052329,0.047784,0.052329],
[1589846400000,0.049656,0.053302,0.049656,0.053302]
]
in A1, and I get the individual values by this simplier way :
function myArray(){
var f = SpreadsheetApp.getActiveSheet();
var result = eval(f.getRange('A1').getValue());
f.getRange(2,1,result.length,result[0].length).setValues(result)
}

Laravel skip and delete records from Database

I'm developing an app which needs to record a list of a users recent video uploads. Importantly it needs to only remember the last two videos associated with the user so I'm trying to find a way to just keep the last two records in a database.
What I've got so far is the below, which creates a new record correctly, however I then want to delete all records that are older than the previous 2, so I've got the below.
The problem is that this seems to delete ALL records even though, by my understanding, the skip should miss out the two most recent records,
private function saveVideoToUserProfile($userId, $thumb ...)
{
RecentVideos::create([
'user_id'=>$userId,
'thumbnail'=>$thumb,
...
]);
RecentVideos::select('id')->where('user_id', $userId)->orderBy('created_at')->skip(2)->delete();
}
Can anyone see what I'm doing wrong?
Limit and offset do not work with delete, so you can do something like this:
$ids = RecentVideos::select('id')->where('user_id', $userId)->orderByDesc('created_at')->skip(2)->take(10000)->pluck('id');
RecentVideos::whereIn('id', $ids)->delete();
First off, skip() does not skip the x number of recent records, but rather the x number of records from the beginning of the result set. So in order to get your desired result, you need to sort the data in the correct order. orderBy() defaults to ordering ascending, but it accepts a second direction argument. Try orderBy('created_at', 'DESC'). (See the docs on orderBy().)
This is how I would recommend writing the query.
RecentVideos::where('user_id', $userId)->orderBy('created_at', 'DESC')->skip(2)->delete();

In a Big Table, is it normal to key values in child (sub) collections?

I'm using Google App Engine and thus Big Table.
I have a person entity that looks like this:
{
// This property would be encoded into JSON and saved un-indexed as db.Text()
phone_numbers:
{
'hHklams8akjJkaJSL': // <-- Should I key this object?
{
number:'555-555-5555',
type:'mobile',
},
etc...
},
// This property is an array of strings.
// It is searchable so that a query could be run to find all
// people with a particular phone number:
// "SELECT * FROM person WHERE phone_number_search_property =
// '5555555555'"
phone_number_search_property:['5555555555','other phone numbers...'],
first_name:'...',
etc...
}
The phone_number property is stored as a blob of unindexed text in JSON format (db.Text). If I want to refer to a particular phone number in this situation, I decode the json, then get the phone number with the particular key that I am looking for.
The phone_number_search_property is used for searching. It enables a search by phone number: "SELECT * FROM person WHERE phone_number_search_property = '5555555555'"
What is a good way to refer to a phone number inside of an entity in this situation? Here, I have each value keyed using a UUID. Is this a "normal" and accepted way of doing things? If not, what is?
Thanks!
If data object is really just part of another object and is never accessed without the "parent" object (as is the case with phone number and person) then IMHO it's ok to serialize it and store it inside the "parent" object. So what you did is OK.
You search persons by phone number, so the solution to have additional property with (normalized) phone numbers is working. If you'd need to search on additional property, then it would not work (e.g. limiting search to only mobile numbers).
Why do you key serialized phone numbers by a hashed string (I assume you generate it via UUID.fromString(String))? Just use the (normalized) phone number - it is unique.

About indexes of GAE datastore

I have a following model in the GAE app.
class User
school_name = db.StringProperty(Indexed=True)
country = db.StringProperty(Indexed=True)
city = db.StringProperty(Indexed=True)
sex = db.StringProperty(Indexed=True)
profession = db.StringProperty(Indexed=True)
joined_date = db.DateTimeProperty(Indexed=True)
And I want to filter the users by combinations of these fields. Result of the filter should show a user at first who is joined recently. So which means any query end by order operation, I suppose. like that:
User.all().filter('country =','US').filter('profession =','SE').order('-joined_date')
User.all().filter('school_name =','AAA').filter('profession =','SE').order('-joined_date')
....
User.all().filter('sex =','Female').filter('profession =','HR').order('-joined_date')
All these fields combination would be C(5,1)+C(5,2)+...+C(5,5) = 31.
My question is to implement it, do I need to create indexes for all these cases(31) in the Google AppEngine. Or can you suggest other way to implement it?
Note: C(n,k) is combination formula, see more on http://en.wikipedia.org/wiki/Combination
Thanks in advance!
You have several options:
Create all 31 indexes, as you suggest.
Do the sorting in memory. Without a sort order, all your queries can be executed with the built-in merge-join strategy, and so you won't need any indexes at all.
Restrict queries to those that are more likely, or those that eliminate most of the non-matching results, and perform additional filtering in memory.
Put all your data in a ListProperty for indexing as "key:value" strings, and filter only on that. You will need to create multiple indexes with different occurrence counts on that field (eg, indexing it once, twice, etc), and it will result in the same number of index entries, but fewer custom indexes used.

Retrieve last row from the Google DataStore Java

I want to retrieve the last row from the data store so how can i do that??
I know the long method i.e
for(Table_name e: resultset)
{
cnt++;
}
results.get(cnt).getvalue();
I have String with (number) as primary key.can i use it to get descending order???
Is there any method through which i can get the last row???
You should probably sort in the opposite order (if possible for your query, the data store has some restrictions here) and get the first result of that.
Also, if you store numbers in String fields the order may not be what you want it to be (you might need padding here).

Resources