Firebase Structure
Periods
+Period1
+Period10
+Period2
+Period3
+Period4
I am getting the value as it is. But i want to be sorted like Period1, Period2, Period3..,Period10
Referring to :
https://firebase.google.com/docs/database/web/lists-of-data#data-order
When using orderByKey() to sort your data, data is returned in ascending order by key.
Children with a key that can be parsed as a 32-bit integer come first, sorted in ascending order.
Children with a string value as their key come next, sorted lexicographically in ascending order.
You could avoid the "Period" as a redundancy as it is implied from the table and use the numeric id directly (not recommended by firebase) or use the push to generate the keys (ids) native to firebase.
The Firebase Database sorts strings lexicographically. And in alphabetical order Period10 comes before Period2.
To ensure the lexicographical order also matches the numerical order that you're looking for, you can consider padding the numbers:
Periods
+Period001
+Period010
+Period002
+Period003
+Period004
With this padding, the lexicographical order matches the numerical ordering that you're looking for. Of course the amount of padding will depend on the maximum number you realistically expect.
Alternatively you can simply store a Period property with a numeric value in each child node and order on that. In that case you can also use push IDs for the keys, as Alex said:
Periods: {
-Laaaaaa: {
Period: 1
},
-Laaaaab: {
Period: 10
},
-Laaaaac: {
Period: 2
},
-Laaaaad: {
Period: 3
},
-Laaaaae: {
Period: 4
}
}
Now you can query ref.orderByChild("Period") and the children will be returned in the wanted numerical order.
Related
Question a:
(i) Write a JavaScript code fragment that obtains four strings from text fields, stores them in an array, uses the sort function to sort it into ascending lexicographical order, and displays the sorted array in a presentation tag on the HTML page from which the script was invoked. All interactions with the document object model should be done using JQuery. You should assume that the input fields have id attributes id1, id2, id3, and id4, and the presentation tag has the id attribute sorted
Solution I found:
$(document).ready(function(){
var strings =[$("#id1").val(),$("#id2").val(),$("#id3").val(),$("#id4").val()];
strings.sort();
$("#sorted").text(strings);
alert(strings);
});
I have a question about that solution: What is the alert(strings); line for? I know what the alert function does but I don't see the question asking for it.
(ii) Describe how the code produced for part (a) would need to be modified to sort numbers into ascending numerical order
It seems to be the code above already sorts numbers into ascending numerical order, am I wrong?
What is the alert(strings); line for?
Just to show the result.
It seems to be the code above already sorts numbers into ascending numerical order, am I wrong?
That's incorrect. If you don't provide a callback, sort defaults to a lexicographic sort (loosely speaking, it sorts alphabetically), converting the elements to strings (for the sort comparison only) if necessary:
const a = [3, 10, 7, 20];
a.sort();
console.log(a);
Notice how 10 comes before 3, because the string "10" sorts before the string "3" in a lexicographic sort, because "1" is before "3".
I am trying to sort my dynamo db results by the sort and key and also get a range of values based on the sort key and i keep getting invalid key condition expression error. basically im trying to get a range of values based on my sort key and also sort them.
example of saved db item:
{
id: ORDER_287d6df3-bd9f-472d-87ef-ee9b810b5874
issued_at: 2021-05-07T15:09:11.894Z
base_cur: NGN
orderRate(GSI): SELL#500
quantity: 300
quantityRemaining: 300
quantityRemoved: 0
quote_cur: GBP
rate: 500
side: SELL
ticker(GSI): GBP#NGN
}
what i have tried:
const params = {
TableName: process.env.ORDERS_TABLE_NAME,
IndexName: 'ticker_orderRate',
KeyConditionExpression: `ticker = :ticker and orderRate between :maxRate and :baseRate`,
ExpressionAttributeValues: {
':ticker': `${quote_cur}#${base_cur}`,
':maxRate': `${side === 'BUY' ? 'SELL' : 'BUY'}#${rate}`,
':baseRate': `${side === 'BUY' ? 'SELL' : 'BUY'}#0.00`,
}
};
the rate is a number that comes from an SNS topic.
Error message:
ERROR: ValidationException: Invalid KeyConditionExpression: The BETWEEN operator requires upper bound to be greater than or equal to lower bound; lower bound operand: AttributeValue: {S:BUY#620}, upper bound operand: AttributeValue: {S:BUY#0.00}
is there a way i can transform the rate and the base rate to numbers while querying the database? and also how do i sort by ascending order?
Thanks for the help
The issue is in your BETWEEN clause. As the erorr message states, the upper bound (the second value) must be greater than or equal to the lower bound (the first value).
There are a few things to consider here.
Remember, this is a string that you are sorting, not a number. You'll need to make some adjustments to handle that.
You need to make sure the length of the number is always the same. This can be accomplished by zero-padding the value (e.g. 1.23 becomes 001.23). Make sure you zero pad to a value that will always be as long or longer than the biggest number you expect.
If you support negative values then you need to be explicit on positive values too. Include a plus (+) on positive numbers.
Dynamically adjust your upper and lower bounds to be in the right order. If the first value is less than the second leave them, if the first value is greater than the second then swap their order.
Key Condition Expression
I've read this [SO post][1], it has helped, but it looks like it has played around with the data...
I have read in two CSV files that look like this:
word, frequency
random, 462546
stupid, 34652
dumb, 4346
I've merged them, which works. I've sorted them, however, it half works. The sorting function sorts the two array of objects as if they were separate. What I mean by this, is that my two arrays of objects merge together, but it has merged them one after another. Then sorted one array of objects, then sorted the other, without sorting them as one whole array, it's sorting them as two arrays.
A link to my CSV files is here enter link description here
d3.csv("data/ArsenalDictionary.csv", function(error1, Arsenal) {
d3.csv("data/ChelseaDictionary.csv", function(error2, Chelsea) {
var selected = d3.merge([Arsenal, Chelsea]);
selected.sort(function(a, b){ return d3.descending(a[2], b[2]); })
console.log(selected);
});
});
Your array selected isn't getting sorted because you are attempting to sort the objects by a non-existent property.
The elements of your array are objects with two properties, "words" and " frequency" (note the leading space in the latter). You are attempting to sort them by a property named 2, which they don't have.
You would have better luck sorting them by the frequency property:
selected.sort(function(a, b){ return d3.descending(a[" frequency"], b[" frequency"]); });
Note however that this doesn't entirely do what you expect: the frequencies end up in the order 94, 9, 9, 9, ..., 8, 8, 8, ..., etc. This is because they have been sorted as strings, not as numbers.
To deal with this either convert the values to numbers while sorting (note the extra + signs):
selected.sort(function(a, b){ return d3.descending(+a[" frequency"], +b[" frequency"]); });
Alternatively, you can convert the frequencies to numbers as part of reading in the files:
function mapRow(row) {
return { "words": row["words"], " frequency": +row[" frequency"] };
}
d3.csv("ArsenalDictionary.csv", mapRow, function(error1, Arsenal) {
d3.csv("ChelseaDictionary.csv", mapRow, function(error2, Chelsea) {
// ...
The former is more convenient but the latter may come in more useful if you want to do other things with the numbers, such as add up two counts if both files use the same word. (world appears in both files).
I'm using this query to verify if data exists on my Firebase (using AngularFire2)
let aux = this.afData.list("/drivers", { query: { orderByChild: '/accountHistory/approved', equalTo: null } });
Works pretty fine, but i also need to make an inverse query.
Like this
let aux = this.afData.list("/drivers", { query: { orderByChild: '/accountHistory/approved', equalTo: !null } });
The problem is. This second query, only returns if the value is TRUE, i'm storing a TIMESTAMP on /driveruid/accountHistory/approved'
There is any way to only verify if the Value exist or doesn't exist?
Thanks!
From the Firebase docs, queries with orderByChild return lists in the following order :-
Children with a null value for the specified child key come first.
Children with a value of false for the specified child key come next. If multiple children have a value of false, they are sorted lexicographically by key.
Children with a value of true for the specified child key come next. If multiple children have a value of true, they are sorted lexicographically by key.
Children with a numeric value come next, sorted in ascending order. If multiple children have the same numerical value for the specified child node, they are sorted by key.
Strings come after numbers and are sorted lexicographically in ascending order. If multiple children have the same value for the specified child node, they are ordered lexicographically by key.
Objects come last and are sorted lexicographically by key in ascending order.
While your first query works fine, for your second query you could try the following code.
let aux = this.afData.list("/drivers", { query: { orderByChild: '/accountHistory/approved', startAt: false });
By doing this, your query results would not contain data with a value of null for your child node.
Though, I would recommend that you make sure that the data at the child node is of the same type for all the nodes to minimise the chances of Class cast exceptions and other errors. This is more of a hack.
I'm dealing with the library qs in Node.js, which lets you stringify and parse query strings.
For example, if I want to send a query with an array of items, I would do qs.stringify({ items: [1,2,3] }), which would send this as my query string:
http://example.com/route?items[0]=1&items[1]=2&items[2]=3
(Encoded URI would be items%5B0%5D%3D1%26items%5B1%5D%3D2%26items%5B2%5D%3D3)
When I do qs.parse(url) on the server, I'd get the original object back:
let query = qs.parse(url) // => { items: [1,2,3] }
However, the default size of the array for qs is limited to 20, according to the docs:
qs will also limit specifying indices in an array to a maximum index of 20. Any array members with an index of greater than 20 will instead be converted to an object with the index as the key
This means that if I have more than 20 items in the array, qs.parse will give me an object like this (instead of the array that I expected):
{ items: { '0': 1, '1': 2 ...plus 19 more items } }
I can override this behavior by setting a param, like this: qs.parse(url, { arrayLimit: 1000 }), and this would allow a max array size of 1,000 for example. This would, thus, turn an array of 1,001 items into a plain old JavaScript object.
According to this github issue, the limit might be for "security considerations" (same in this other github issue).
My questions:
If the default limit of 20 is meant to help mitigate a DoS attack, how does turning an array of over 20 items into a plain old JavaScript object supposed to help anything? (Does the object take less memory or something?)
If the above is true, even if there is an array limit of, say, 20, couldn't the attacker just send more requests and still get the same DoS effect? (The number of requests necessary to be sent would decrease linearly with the size limit of the array, I suppose... so I guess the "impact" or load of a single request would be lower)