Firebase real time database compound query combining text and date - javascript

I'm trying to make a compound query (combining two children). What I want to do is fetch objects that are older than 5 minutes AND also are of a type.
So I've combined the children type and date into a new child called type_date and I do my query like this:
const now = Date.now();
const fiveMinutesMs = 5*60*1000;
const fiveMinutesAgo = now - fiveMinutesMs;
const fiveMinutesAgoQuery = "type_" + fiveMinutesAgo;
ref.orderByChild('type_date').endAt(fiveMinutesAgoQuery).once('value');
Only thing is that it doesn't work. It's giving me results of objects which doesn't even have the type_date child.

Try startAt instead of endAt. I hope it works.

EDIT: Oops I was too quick.... it works only if I'm only filtering on the date string but not together with the prepended type which I want...
So this works:
const fiveMinutesAgoIso = new Date(fiveMinutesAgo).toISOString();
const fiveMinutesAgoQuery = String(fiveMinutesAgoIso);
But not:
const fiveMinutesAgoIso = new Date(fiveMinutesAgo).toISOString();
const fiveMinutesAgoQuery = "type_" + fiveMinutesAgoIso;

Just make a Compound queries as doc says :
const fiveMinutesAgoIso = new Date(fiveMinutesAgo).toISOString();
ref.where("type", "==", TYPE_YOU_WANT).orderByChild('type').endAt(fiveMinutesAgoQuery).once('value');

Related

Split out props.location.search value

I'm trying to split out the values from props.location.search in React/Redux. I've successfully obtained the mixOne split however I can't seem to return the value of quantity. Here's my code:
const mixOne = props.location.search
? String(props.location.search.split("mixOne=")[1])
: "None";
const quantity = props.location.search
? Number(props.location.search.split("=")[1])
: 1;
And here's the URL that gets generated:
const addToCartHandler = () => {
props.history.push(
`/Cart/${productId}?quantity=${quantity}?mixOne=${mixOne}`
);
};
As you can see quantity returns null, when I need the value selected
props.location.search.split("=") on "?quantity=1?mixOne=Grape" would return [ '?quantity', '1?mixOne', 'Grape' ] since the next = is not until after mixOne.
There's a few different fixes here.
Your query string is invalid– a ? denotes the start of the query string. Separate parameters should be split up using & ampersand characters. It should look like this: ?quantity=1&mixOne=Grape
If you follow the standard here, you can then split it two ways: by = and then by & to get the different parameters. However, there is an easier way.
Using the new-ish URLSearchParams API, you can parse your parameters in a predictable way:
// Use the constructor with your `props.location.search`
const queryParams = new URLSearchParams(props.location.search);
// Use the getters to grab a specific value
const quantity = queryParams.get("quantity");
// Ensure it's a number for safety
const quantityNum = Number(quantity);
// ... the rest of your code here
The query is wrong. You're using double question marks. The second ? should be replaced with &.
?quantity=1&mixOne=Grape

path combined with filter - with Ramda

I am querying data from an API which has nested object properties that I need to access.
const players = teamsData && teamsData.team && teamsData.team.players;
I am using path to get this data.
const players = path(['team', 'players'], teamsData);
This works but when I combine with filter I get an error.
Ideally I want to use pipe and combine this with Ramda's filter method.
My code looks like this:
const injuredPlayers = pipe(
path(['team', 'players'], teamsData),
filter(player => player.isInjured)
);
it does look like the players variable equals
const players = path(['team', 'players'], teamsData);
at least from the code you wrote
will continue here if it's not a problem
at first I would prefer to use pathOr instead is going to look like this
const pathTeamPlayers = R.pathOr([], ['team', 'players']);
const isInjured = player => player.injured
const filterInjured = R.filter(isInjured)
const teamDataToInjuredPlayers = R.pipe(
pathTeamPlayers,
filterInjured,
);
/* result */
teamDataToInjuredPlayers(teamData)
If you just want the list of injured players, you can write
const injuredPlayers =
filter (player => player.isInjured) (path (['team', 'players'], teamsData)
If you want a function that will retrieve that information from teamsData, then you can write
const getInjuredPlayers = pipe (
path('[team', 'players']),
filter (prop ('isInjured'))
)
(or use pathOr with [] to increase reliability) and call it with
const injuredPlayers = getInjuredPlayers (teamData)
Your code is combining these two distinct styles.

In protractor: How do I create a method that only sends keys I specify

I have a method called populateProvidedValuesForNewMandate that looks like this
exports.populateProvidedValuesForNewMandate = (team, assignee, disputeValue, lawField,
subjectOfDispute, party, fileReference, costUnit, clientUnit, sideEffect, comment) => {
const teamInput = element(by.css('div#team input'));
const assigneeInput = element(by.css('div#assignee input'));
const disputeValueInput = element(by.id('dispute_value'));
const lawFieldInput = element(by.css('div#law_field input'));
const subjectOfDisputeInput = element(by.id('subject_of_dispute'));
const partyInput = element(by.id('party'));
const fileReferenceInput = element(by.id('file_reference'));
const costUnitInput = element(by.css('div#cost_unit input'));
const clientUnitInput = element(by.id('client_unit'));
const sideEffectInput = element(by.css('div#side_effect input'));
const mandateComment = element(by.id('mandate_comment'));
// TODO: Figure out how to choose these dynamically as well
// relevantCase, risReportRelevant, economicRelevance, activePassive
const relevantCaseInput = element(by.css(".relevant_case input[value='no']"));
const riskReportRelevantInput = element(by.css(".risk_report_relevant input[value='no']"));
const economicRelevanceInput = element(by.css("label[for='economic_relevance']"));
const activePassiveInput = element(by.css(".active_passive input[value='passive']"));
teamInput.sendKeys(team);
assigneeInput.sendKeys(assignee);
disputeValueInput.sendKeys(disputeValue);
lawFieldInput.sendKeys(lawField);
subjectOfDisputeInput.sendKeys(subjectOfDispute);
partyInput.sendKeys(party);
fileReferenceInput.sendKeys(fileReference);
costUnitInput.sendKeys(costUnit);
clientUnitInput.sendKeys(clientUnit);
sideEffectInput.sendKeys(sideEffect);
mandateComment.sendKeys(comment);
// TODO: Figure out how to choose these dynamically as well
// relevantCase, risReportRelevant, economicRelevance, activePassive
browser.actions().mouseMove(relevantCaseInput).doubleClick().perform();
browser.actions().mouseMove(riskReportRelevantInput).click().perform();
browser.actions().mouseMove(economicRelevanceInput).click().perform();
browser.actions().mouseMove(activePassiveInput).click().perform();
};
and here is an example of its use case
values.populateProvidedValuesForNewMandate(texts.DISPUTE_VALUE, texts.PARTY, texts.CLIENT_UNIT,
texts.SIDE_EFFECT, texts.COMMENT);
The method fills out the specified values that lie within a file called texts.js into the appropriate fields. The problem is that I get the error message: 'each key must be a number of string; got undefined' meaning that this method doesn't work because I have to send the keys for each specified variable in the method.
I really want to avoid sending empty strings for this method (especially because it won't work, I've tried it out -> I get a error from the app itself, not protractor/selenium).
How can I turn this method into one that only considers the specified variables in the test cases.
Also as you can see from my comment, I am trying to figure out how to do this for the checkbox and radio buttons as well. If anyone has a hint, I'd really appreciate it
Honestly, only you can answer the question. Because there are hundreds of ways to fo this, and some may work better than another. So to us it's silly to make guesses which way is the best for you. So I'll give one example and hopefully you can take it from here
One way is to make the method accept an object and check if a property has been passed
function fillForm(obj) {
if (obj.hasOwnProperty('team')) teamInput.sendKeys(team);
if (obj.hasOwnProperty('assignee')) assigneeInput.sendKeys(assignee);
if (obj.hasOwnProperty('disputeValue')) disputeValueInput.sendKeys(disputeValue);
// ...
}
and then call it
fillForm({
assignee: texts.ASIGNEE,
disputeValue: texts.DISPUTE_VALUE
})
so it will skip sending keys to team field

How to update a value using in firebase realtime database?

So I am using Cloud Functions at the moment. What I am doing is this:
export const onMessageCreate = functions.database.ref('/Users/{user}/{message}/{text}').onCreate((snapshot, context) => {
const data = snapshot.val()
const changedData: string = change(byteData.text)
return snapshot.ref.update({id: compressedByteData}) //This is the problem
})
The change(input: string): string is a custom function of mine that just replaces every occurrence of the word happy birthday with a birthday cake emoji. Thing is however that in my reference which looks like this: "/Users/{user}/master/{messageGroup}/content/{message}" I want to update the value of text. Since, however, I don't know what {text} is I can't store it in the correct location. Does anyone have some suggestions?
The change() function is:
function change(data:string):string {
return data.replace(/\bhappy-birthday\b/g, '🎂')
}
Here is the Firebase node picture:
Firebase Node Setup
So I want to change the 01, 02, 03 with my Cloud Functions (the values don't matter).
Visual Representation of what I want to do:
Visual Representation
New Update following your comments:
If I understand correctly your last comments, this should do the trick:
export const onMessageCreate = functions.database.ref('/Users/{user}/master/{messageGroup}/content/{message}').onCreate((snapshot, context) => {
const data = snapshot.val();
const changedData: string = change(byteData.text);
const user = context.params.user;
const messageGroup = context.params.messageGroup;
return admin.database().ref(`/Users/${user}/master/${messageGroup}/content`).update({4f3f: changedData});
})
Update following your comments:
Sorry but it not 100% clear what you want to update.
If you want "change the value of /Users/{user}/master/{messageGroup}/content/{message} when (you) create the value at /Users/{user}/master/{messageGroup}/content/{message}" with the value of changedData, just do as follows:
export const onMessageCreate = functions.database.ref('/Users/{user}/master/{messageGroup}/content/{message}').onCreate((snapshot, context) => {
const data = snapshot.val();
const changedData: string = change(byteData.text);
return snapshot.ref.update({message: changedData});
})
Within your Cloud Function you will be able to get the path values by doing
const user = context.params.user;
const message = context.params.message;
and then build the desired node reference.
As you can read in the documentation:
You can specify a path component as a wildcard by surrounding it with curly brackets; ref('foo/{bar}') matches any child of /foo. The
values of these wildcard path components are available within the
EventContext.params object of your function. In this example, the
value is available as event.params.bar.

firebase -> date order reverse

I am currently making an app using Firebase.
It is one of those bulletin boards that can be seen anywhere on the web.
But there was one problem.
This is a matter of date sorting.
I want to look at the recent date first, but I always see only the data I created first.
postRef.orderByChild('createData').startAt(reverseDate).limitToFirst(1).on('child_added',(data)=>{
console.log(data.val().name + data.val().createData);
})
result - >hello1496941142093
My firebase tree
My code is the same as above.
How can I check my recent posts first?
How Do I order reverse of firebase database?
The Firebase Database will always return results in ascending order. There is no way to reverse them.
There are two common workaround for this:
Let the database do the filtering, but then reverse the results client-side.
Add an inverted value to the database, and use that for querying.
These options have been covered quite a few times before. So instead of repeating, I'll give a list of previous answers:
Display posts in descending posted order
Sort firebase data in descending order using negative timestamp
firebase sort reverse order
Is it possible to reverse a Firebase list?
many more from this list: https://www.google.com/search?q=site:stackoverflow.com+firebase+reverse%20sort%20javascript
You can simply make a function to reverse the object and then traversing it.
function reverseObject(object) {
var newObject = {};
var keys = [];
for (var key in object) {
keys.push(key);
}
for (var i = keys.length - 1; i >= 0; i--) {
var value = object[keys[i]];
newObject[keys[i]]= value;
}
return newObject;
}
This is how I solved it:
First I made a query in my service where I filter by date in milliseconds:
getImages (): Observable<Image[]> {
this.imageCollection = this.asf.collection<Image>('/images', ref => ref.orderBy('time').startAt(1528445969388).endAt(9999999999999));
this.images = this.imageCollection.snapshotChanges().pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data() as Image;
const id = a.payload.doc.id;
return { id, ...data };
}))
);
return this.images;
}
Then to get the newest date first I added this to my component where I call the method from my service:
let date = new Date;
let time = 9999999999999 - date.getTime();
console.log(time);
I pass the time let as the date. Since a newer date will be a bigger number to deduct from the 9999999999999, the newest date will turn up first in my query inside my service.
Hope this solved it for you
If you want to display it in the front end, I suggest that after you retrieve the data, use the reverse() function of JavaScript.
Example:
let result = postRef
.orderByChild("createData")
.startAt(reverseDate)
.limitToFirst(1)
.on("child_added", data => {
console.log(data.val().name + data.val().createData);
});
result.reverse();
Ive ended changing how I create my list on the frontend part.
was
posts.add(post);
changed to
posts.insert(0, post);
You could use a method where you save the same or alternate child with a negative value and then parse it.
postRef.orderByChild('createData').orderByChild('createData').on('child_added',(data)=>{
console.log(data.val().name + data.val().createData);})
Far more easier is just use Swift's reversed():
https://developer.apple.com/documentation/swift/array/1690025-reversed
https://developer.apple.com/documentation/swift/reversedcollection
let decodedIds = try DTDecoder().decode([String].self, from: value)
// we reverse it, because we want most recent orders at the top
let reversedDecodedIds = decodedIds.reversed().map {$0}
orderBy("timestamp", "desc")
I think you can give a second argument name "desc".
It worked for me

Categories