How can I retrieve multiple objects by key? - firebase

I was just looking in the docs but couldn't find anything.
So my web app has a structure that's similar to the one in this site.
For the sake of simplicity, let's say my app has only questions which are catalogued by tags. As suggested in the docs, we store our data with a flat, non-normalized structure (E.g.
{
"questions": {
...
},
"tags": {
"tag1": {
"name": "Tag1",
"questions": { "0": true, "1": true }
},
"tag2": {
"name": "Tag2",
"questions": { "2": true, "3": true }
}
}
}
), rather than a normalized structure without data replication like:
{
"questions": {
"0": { "title": ..., "tag": ... },
"1": { "title": ..., "tag": ... },  
}
}
One of the advantages of using the first structure is that I can search for questions that have a certain tag without downloading all the data of all of the questions first: querying for /tags/tag1/questions, will return all the object with all of the question's keys. Now, I can query for the questions, but how do I do that?
I don't want to make ten requests for every question, it seems a waste of time and performance, but I couldn't find a way to make Firebase filter by multiple keys. It seems I can only give Firebase one input at a time. I think (and I hope) I am missing something here. What is it?
If I really can't do this, how do I search by tags here?

Related

Not allowed duplicate record

It's a simple check to restrict duplicate entries, i can't find a way to do it, thought.
Shema:
{
"languages": {
"unique_id": {
"code": "Fr",
"name": "French"
},
"unique_id": {
"code": "En",
"name": "English"
}
}
}
Security rule that i've tried:
service cloud.firestore {
match /databases/{database}/documents {
match /languages/{language} {
allow write: if !(resource.data.hasAny([request.resource.code]));
}
}
}
For instance :this must not allowed
{
"languages": {
"unique_id": {
"code": "Fr",
"name": "French"
},
"unique_id": {
"code": "En",
"name": "English"
},
"unique_id": {
"code": "Fr",
"name": "German"
}
}
}
There really isn't a good way to do it with the current schema. Below are 2 methods with different trade-offs you could explore.
Invert Data Model
Change your data model to make uniqueness the only option, which removes the need to validate.
{
"languages": {
"Fr": {
"name": "French"
},
"En": {
"name": "English"
}
}
}
Note in this model it isn't possible to add your broken case.
To query for any document with a particular language code, e.g. 'En', you can do:
.where("En.name", ">", "")
Pros:
Non-unique language codes are impossible
Simple to implement
Cons:
You won't be able to do composite indexes on language code or name
Post-validation
Alternatively, you can set up a Cloud Functions to trigger on any writes. This Function can then have code to do the uniqueness enforcement for you. It would then follow some logic you define if it detects an issue, such as either flagging the document as bad or removing & logging the subsequent non-unique entries.
Pros:
You can do composite indexes with languages.unique_id.code and languages.unique_id.name
Cons:
Incorrect data can exist for short periods of time
Harder to give errors back to the client
Post-Update
Rather than allowing clients to update the language codes, require them to write to a subcollection. Have Cloud Functions trigger on update to the sub-collection, then update the master document if it pasts your checks. Optionally you can then delete the document in the subcollection or leave it as an audit trail.
Pros:
You can do composite indexes with languages.unique_id.code and languages.unique_id.name
Document will always be correct
Cons:
Data in the document can be stale for short periods of time
Harder to give errors back to the client

FHIR : adding a custom extension

I would like to add to add a custom extension to my Schedule resource.
In my app, Schedule have visit motives (reasons). I know there's a list of classified appointments / encounter reasons but I would like to use mine.
I have something like this :
{
"resourceType":"Schedule",
"identifier":"logical_id",
"type":"schedule_speciality",
"actor":{
"practioner_id":"identifier",
"practioner_name":"practioner name"
},
"external_id":{
"extension":[
{
"url":"http://api.test.com/fhir/schedule/external_id",
"valueIdentifier":"external_id"
}
]
},
"visit_motives":{
"extension":[
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive3"
}
]
},
"practice_id":{
"extension":[
{
"url":"https://api.test.com/fhir/schedule/practice_id",
"valueIdentifier":"practice_id"
}
]
}
}
I'm not sure about this part :
"visit_motives":{
"extension":[
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive3"
}
]
}
Is it correct to add an extension this way ? There are always multiple visit motives for a specific schedule so I have to list them.
I also have seen this kind of things :
"visit_motives": {
"coding": [
{
"system": "https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"code": "visit_motive1"
}
]
}
Which one is the correct one or am I wrong ?
There are several issues here:
It seems odd to capture a "reason" on a schedule. A schedule says when a particular clinician or clinic or other resource is available. E.g. "Dr. Smith takes appointments Mon/Wed/Fri from 1pm-4pm". So if you were to capture a reason on the resource, it would reflect "Why does Dr. Smith have a schedule?" Typically reasons are captured for an individual Appointment. That's the resource that reserves a particular slot for a planned visit. And Appointment already has an element for reason where you're free to use your own codes or just send text.
You have extensions to convey identifiers, but Schedule already has an element for identifiers. Why would you use extensions instead of the standard element? Note that you can use the "system" and/or "type" components to differentiate different kinds of identifiers.
You're sending "identifier", "type", "name", etc. as simple strings - but they're complex data types, so you need to communicate the child elements
actor is of type Reference - that means you need to point to the Practitioner resource. You can't send the properties in-line. (If the Practitioner only exists in the context of the Schedule, you could use the "contained" approach which would use an internal reference, but containment doesn't seem to make sense in this use-case.
The URL for your extension contains ValueSet, which isn't correct - extensions are all structure definitions. Also, there shouldn't be a # symbol in the URL.
Your syntax for extensions is incorrect. You can't introduce new properties in FHIR. The property name for all extensions is just "extension". You differentiate by the URL. So your syntax should be:
{
"resourceType":"Schedule",
"id":"logical_id",
"extension": [
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motive",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motive",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motives",
"valueString":"vist_motive3"
}
],
"identifier": [
{
"system": http://api.test.com/fhir/NamingSystem/external_id",
"value": "external_id"
}
{
"system": http://api.test.com/fhir/NamingSystem/practice_id",
"value": "practice_id"
}
]
"type": {
"coding": {
"system": "http://somewhere.org/fhir/CodeSystem/specialties",
"code": "schedule_speciality"
},
"text": "Some text description of specialty"
},
"actor":{
"reference": "http://myserver.org/fhir/Practitioner/12345"
"display": "Dr. smith"
}
}

Firebase Data Structure Guidance

I have been researching Firebase as an alternative to the recently deprecated Dropbox Datastore API. I read the articles about structuring data, but I’m still a little unclear.
I have a bunch of users:
users
- name
- email
...and each user has three database “tables”, aircraft, entries, and customFields.
aircraft
- name
- category
- make
entries
- flightDate
- departure
- destination
customFields
- name
- type
So would my Firebase data structure look something like this?
{
“users”: {
“bob”: {
“name”: …
“email”: …
},
“sally”: {
“name”: …
“email”: …
}
},
“aircraft”:{
???
},
“entries”:{
???
},
“customFields”:{
???
}
}
Thanks in advance.
Are you familiar with OOP? Each "table" is an object. Personally I would do something as follows. Since I don't understand what you're trying to achieve with the database and their objects, this may not be correct:
{
"user": {
"name": "bob",
"aircraft": {
"name": "name"
},
"entries": {
"flightdate": "27/05/2015"
}
}
}
Think in objects, not tables. Think parent and child.
But in your example, if each object (user, aircraft, entries etc.) was plurals, you can treat them as a "table", it would just be an array of objects:
{
"aircrafts":[
{
"id":1,
"name": "name"
},
{
"id":2,
"name": "name"
}
]
}
Edit: My first example was if each user had an aircraft, in retrospect it was silly, but my point still stands.

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