structure data for different queries - firebase

I am learning firebase and trying to find the best way to structure my data.
Use an example of a simple leave application. Employees can submit and view their leaves. Managers can approve leaves.
Option 1
"leaves": [
{
"employee": "pCIUfttSrXQ1dLPDwH7j9GExCkA2",
"date": "2017-03-01",
"status": "pendingApproval",
},
{
"employee": "YSJCAe4wZdYCplA3e0ejMqzQmEF3",
"date": "2017-01-01",
"status": "approved"
}]
With option 1, filtering will be required in both cases:
When employee lists his leave history (filter by "employee")
When manager lists all the pending leaves (filter by "status=pending")
Option 2
"leaves":
{
"pCIUfttSrXQ1dLPDwH7j9GExCkA2" : [
{
"date": "2017-03-01",
"status": "pendingApproval"
}
],
"YSJCAe4wZdYCplA3e0ejMqzQmEF3" : [
{
"date": "2017-01-01",
"status": "approved"
}
]
}
With option 2, no filtering is required when employee lists his leave history, but filtering is required (and I don't know how) for manager to list pending leaves.
What should be the right way to structure the data? And if it's option 2, how would we filter the pending leaves for all employees?

Use the second option;
For the manager to filter through the pending queries , use:
FIRDatabase.database().reference().child("leaves").queryOrdered(byChild: "status").queryEqual(toValue: "pending").observeSingleEvent(of: .value, with: {(Snapshot) in
print(Snapshot.value!)
// If you have multiple pending request you gotta loop through them
// using for loop, access them as separate entity and operate on them
})

Related

Firestore Pagination : how to set Cursor for startAt using Rest Api

I'm using firebase firestore using Rest API to get data limited by 5 documents only, ordered by a field called LikesCount.
When I want to fetch the next 5 documents I have to use startAt and pass the LikesCount value of the last document from the first 5 documents.
But in this way, it will fetch wrong data when there is another document with the same LikesCount value So I tried and searched a lot about how to pass the last Document id in addition to the LikesCount value But all of them did not work In addition, I tested the pagination using the Web SDK and it was working correctly because you can pass the document snapshot easily, but what does the document snapshot object include? So that we can understand the structure of the Cursor and apply it to the REST API.
I tried to use this method to pass the Document ID as referenceValue
{
"structuredQuery": {
"from": [{
"collectionId": "Users"
}],
"where": {
"compositeFilter": {
"op": "AND",
"filters": []
}
},
"orderBy": [{
"field": {
"fieldPath": "LikesCount"
},
"direction": "DESCENDING"
}],
"startAt":
{ "values": [
{
"integerValue": "6"
},
{
"referenceValue": "projects/myprojectid/databases/(default)/documents/Posts/xEvmJ1LLHwTKVREQfXtX"
}
],
"before": false
},
"limit":5
}
}
But an error will occur : Cursor has too many values.
also, I tried to pass only the referenceValue and it still did not return the correct 5 documents.
Thanks in advance :)
Your orderBy() has 1 field (LikesCount) but your startAt() has 2 fields. I suspect that is the reason for the error message?
Passing the integerValue won't work. If there are 13 results with the value 6, then each time you make the above call you'd get the same first 5 results.
When you say:
I tried only passing the referenceValue and still did not get the correct 5 documents
what documents are you getting? What documents were you expecting to get?

Get the latest document based on a document's property in Azure Cosmos DB

Let's say that I have a Cosmos DB collection with the SQL API that contains a list of messages that people have sent that give their current mood and a timestamp of when the message has been received. People can send messages whenever they want.
In my collection I have something that looks like this:
[
{
"PersonName": "John",
"CurrentMood": "Moody",
"TimeStamp": "2012-04-23T18:25:43.511Z",
"id": "25123829-1745-0a09-5436-9cf8bdcc95e3"
},
{
"PersonName": "Jim",
"CurrentMood": "Happy",
"TimeStamp": "2012-05-23T17:25:43.511Z",
"id": "6feb7b41-4b85-164e-dcd4-4e078872c5e2"
},
{
"PersonName": "John",
"CurrentMood": "Moody",
"TimeStamp": "2012-05-23T18:25:43.511Z",
"id": "b021a4a5-ee92-282c-0fe0-b5d6c27019af"
},
{
"PersonName": "Don",
"CurrentMood": "Sad",
"TimeStamp": "2012-03-23T18:25:43.511Z",
"id": "ee72cb36-4304-06e5-ed7c-1d0ff890de48"
}
]
I would like to send a query that gets the "current" mood of all the user who sent a message (the latest message received for all person).
It's relatively easy to do for each particular user, by combining TOP 1 and ORDER BY
SELECT TOP 1 *
FROM C
WHERE C.PersonName = "John"
ORDER BY C.TimeStamp
But I feel like looping through all my users and running the query for each might be very wasteful in resource and become expensive quickly, but I can't find a way that will work.
To note that I will quickly have a lot of persons who will send a lot of messages.
The common pattern for this is to have two collections, one that stores documents for (user, timestamp -> mood), then a downstream processor using Azure Functions or the Change feed API directly that computes the (user -> latest mood)
[Mood Time series Collection] ==> Lambda ==> [Latest Mood Collection]
And the Latest Mood Collection will look something like this for the data stream above. You then use this for your lookups (which are now key lookups).
{
"PersonName": "Jim",
"LatestMood": "Happy",
"LatestTimeStamp": "2012-05-23T17:25:43.511Z",
"id": "6feb7b41-4b85-164e-dcd4-4e078872c5e2"
},
{
"PersonName": "John",
"LatestMood": "Moody",
"LatestTimeStamp": "2012-05-23T18:25:43.511Z",
"id": "b021a4a5-ee92-282c-0fe0-b5d6c27019af"
},
{
"PersonName": "Don",
"LatestMood": "Sad",
"LatestTimeStamp": "2012-03-23T18:25:43.511Z",
"id": "ee72cb36-4304-06e5-ed7c-1d0ff890de48"
}

Pre-processing Redux state (location for business logic)

I have created an application in react, which has the purpose to find flights and display them in a results window. With filter settings in the sidebar, you are able to filter these results. Currently I am converting the react app to Redux.
I have the following state in my store:
const defaultState = {
flightOffers,
filteredFlightOffers,
filters
}
Where flightOffers is an array of objects with flightresults:
flightOffers = [{
"inboundFlight": {
"departureDate": "2016-06-02",
"departureTime": "09:00",
"departureTimeSpan": "morning",
"arrivalDate": "2016-06-02",
"arrivalTime": "12:32",
"arrivalTimeSpan": "afternoon",
"marketingAirline": {
"companyShortName": "KL",
"name": KLM,
"imageurl": "images/logos/kl.png"
},
"flightNumber": 5131,
"departureAirport": {
"locationCode": "BCN",
"name": "Barcelona"
},
"arrivalAirport": {
"locationCode": "AMS",
"name": "Amsterdam"
}},
];
The state of filteredFlightOffers is the same, but a subset of the flightOffers state object.
And the filters state object has the following format:
filters = [{
"type": "airlines",
"checked": true,
"label": "Air France",
"count": 579
},
{
"type": "airlines",
"checked": true,
"label": "Brittish Airways",
"count": 554
},
{
"type": "airlines",
"checked": true,
"label": "CityJet",
"count": 576
}
];
The flightOffers state object is retrieved by an API call.
The filteredFlightOffers state object should be created based on all the checked / non-checked items in the filters state object, and should be recreated every time a filter is changed.
The filter stateobject will have a changed checked value every time an item is clicked, but also updated count items for all elements every time the new filteredFlightOffers state object is recreated.
Now I have the following questions:
My filters state object is derived from the flightOffers state object and should be created on the fly when the data from the flightOffers is retreived by the API call. Where in the redux pattern is the good place to implement this logic?
I have a dispatcher for my flightOffers state and for my settings state. When a filter setting is clicked, an action will go to the filter dispatcher and return the new filter state. But how can I calculate all the new filter counts based on the flightOffer state? e.g. Do I need to fire a FlightOfferCounter action and give the filter state as input parameter? If so, can I fire this call from my filter reducer? Or do I have to create a FlightOfferCounter reducer which listenes to the same action as the filter reducer? Problem then would be that these reducers cannot be executed in parallel since the flightOfferCounter is based on the checked values in the filter state.
I am reading things about redux thunk (for implementing business logic). Is that something I need here?
Hope my questions are a bit clear.

Serialized Entities displaying only ID

I'm using JMSSerializer and FOSRestBundle. I have a fairly typical object graph, including some recursion.
What I would like to accomplish is that included objects beyond a certain depth or in general are listed only with their ID, but when serialized directly, with all data.
So, for example:
Users => Groups => Users
when requesting /user/1 the result should be something like
{ "id": 1, "name": "John Doe", "groups": [ { "id": 10 }, { "id": 11 } ] }
While when I request /group/10 it would be:
{ "id": 10, "name": "Groupies", "users": [ { "id": 1 }, { "id": 2 }, { "id": 4 } ] }
With #MaxDeph I can hide the included arrays completely, so I get
{ "id": 1, "name": "John Doe", "groups": [] }
But I would like to include just the IDs so that the REST client can fetch them if it needs them, or consult his cache, or do whatever.
I know I can manually cobble this together using groups, but for consistency reasons I was wondering if I can somehow enable this behaviour in my entire application, maybe even with a reference to maxdepth so I can control where to include IDs and where to include full objects?
For the sake of those finding this:
I found no other solution, but doing this with groups works just fine and gives me the result I was looking for.

"Reverse formatting" Riak search results

Let's say I have an object in the test bucket in my Riak installation with the following structure:
{
"animals": {
"dog": "woof",
"cat: "miaow",
"cow": "moo"
}
}
When performing a search request for this object, the structure of the search results is as follows:
{
"responseHeader": {
"status": 0,
"QTime": 3,
"params": {
"q": "animals_cow:moo",
"q.op": "or",
"filter":"",
"wt": "json"
}
},
"response": {
"numFound": 1,
"start": 0,
"maxScore": "0.353553",
"docs": [
{
"id": "test",
"index": "test",
"fields": {
"animals_cat": "miaow",
"animals_cow": "moo",
"animals_dog": "woof"
},
"props": {}
}
]
}
}
As you can see, the way the object is stored, the cat, cow and dog keys are nested within animals. However, when the search results come back, none of the keys are nested, and are simply separated by _.
My question is this: Is there any way provided by Riak to "reverse format" the search, and return the fields of the object in the correct (nested) format? This becomes a problem when storing and returning user data that might possibly contain _.
I do see that the latest version of Riak (beta release) provides a search schema, but I can't seem to see whether my question would be answered by this.
What you receive back in the search result is what the object looked like after passing through the json analyzer. If you need the data formatted differently, you can use a custom analyzer. However, this will only affect newly put data.
For existing data, you can use the id field and issue a get request for the original object, or use the solr query as input to a MapReduce job.

Resources