I am using Firebase Database for my mobile and web application. I wanted to get advise for how to structure the JSON Tree. I have the following use case in mind:
Mobile app user logs in and gets all nearby restaurants in a list. User sets order on one restaurant. The restaurant owner uses web or mobile application to see incoming orders and accepts them. After accepting the order, the mobile app user gets response that his order has been accepted. Now my idea for the structure was the following:
SO we have one node at top level for each restaurant and each restaurant node contains a requests node which saves all the requests for this restaurants.
Is that structure ok or could this be structured better?
Consider a data structure like this, you don't want to retrieve all the request when you get a restaurant and this way, you can get all the requests for a restaurant and all the requests from a particular user.
{
"requests": {
"req1": {
"status": 0,
"time": 1473593287,
"user": { "u2": true }
},
"req2": {
"status": 0,
"time": 1473593227,
"user": { "u1": true }
},
"req3": {
"status": 0,
"time": 1473594287,
"user": { "u1": true }
},
"req4": {
"status": 0,
"time": 1473594227,
"user": { "u2": true }
},
},
"restaurant-requests": {
"resA": {
"req1": true,
"req2": true
},
"resB": {
"req3": true,
"req4": true
}
},
"restaurants": {
"resA": {
"name": "Example Restaurant A",
"address": "1 Example Street"
},
"resB": {
"name": "Example Restaurant B",
"address": "2 Example Street"
}
},
"user-requests": {
"u1": {
"req2": true,
"req3": true
},
"u2": {
"req1": true,
"req4": true
}
},
"users": {
"u1": {
"address": "123 Example Street"
},
"u2": {
"address": "124 Example Street"
},
},
}
That's what I would do..
good luck!
Related
I am integrating Paypal checkout in an Android App using REST APIs provided by Paypal and my country is India so I am following this guide from PayPal.
How I did as per docs:
Get access-token (/v1/oauth2/token) for further api calls.
Use the Create Order API to create a payment (v2/checkout/orders)and in the response we will get approval url at where you need to redirect user to make the payment.
Now my question is how do I know if payment transaction was successful or not in mobile app because I am using WebView in my app to load approval url.
Order is created like this and I load href inside webview:
{
"id": "1KK44573EX7352015",
"status": "CREATED",
"links": [
{
"href": "https://www.sandbox.paypal.com/checkoutnowtoken=1KK44573EX7352015",
"rel": "approve",
"method": "GET"
}
]
}
I did this way:
As soon as Payment is successfully completed by customer the return_url gets called with query parameters : PayerID & token(orderID). At that time we can update user's payment status in our database (Amount is not deducted yet still because order is yet not approved or captured).
After that we can capture our order (Make sure invoice-id is not duplicate) otherwise status will be not completed.
If order is not approved on the time of capture we get this kind of error:
{
"name": "UNPROCESSABLE_ENTITY",
"details": [
{
"issue": "ORDER_NOT_APPROVED",
"description": "Payer has not yet approved the Order for payment. Please redirect the payer to the 'rel':'approve' url returned as part of the HATEOAS links within the Create Order call or provide a valid payment_source in the request."
}
],
"message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id": "47af43e..",
"links": [
{
"href": "https://developer.paypal.com/docs/api/orders/v2/#error-ORDER_NOT_APPROVED",
"rel": "information_link",
"method": "GET"
}
]
}
If there is duplicate invoice-id you will see error at the time of capture:
{
"name": "UNPROCESSABLE_ENTITY",
"details": [
{
"issue": "DUPLICATE_INVOICE_ID",
"description": "Duplicate Invoice ID detected. To avoid a potential duplicate transaction your account setting requires that Invoice Id be unique for each transaction."
}
],
"message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id": "86e0cc7f....",
"links": [
{
"href": "https://developer.paypal.com/docs/api/orders/v2/#error-DUPLICATE_INVOICE_ID",
"rel": "information_link",
"method": "GET"
}
]
}
If there is currency based issue:
{
"name": "UNPROCESSABLE_ENTITY",
"details": [
{
"location": "body",
"issue": "CURRENCY_NOT_SUPPORTED",
"description": "Currency code is not currently supported. Please refer https://developer.paypal.com/docs/integration/direct/rest/currency-codes/ for list of supported currency codes."
}
],
"message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id": "d666b5e5eb0c0",
"links": [
{
"href": "https://developer.paypal.com/docs/api/orders/v2/#error-CURRENCY_NOT_SUPPORTED",
"rel": "information_link",
"method": "GET"
}
]
}
If your order is successfully captured with status as COMPLETED:
{
"id": "8G0042477K865063U",
"status": "COMPLETED",
"purchase_units": [
{
"reference_id": "default",
"shipping": {
"name": {
"full_name": "John Doe"
},
"address": {
"address_line_1": "10, east street",
"address_line_2": "first building",
"admin_area_2": "Mumbai",
"admin_area_1": "Maharashtra",
"postal_code": "400029",
"country_code": "NZ"
}
},
"payments": {
"captures": [
{
"id": "4K670967VH2547504",
"status": "PENDING",
"status_details": {
"reason": "RECEIVING_PREFERENCE_MANDATES_MANUAL_ACTION"
},
"amount": {
"currency_code": "NZD",
"value": "170.00"
},
"final_capture": true,
"seller_protection": {
"status": "ELIGIBLE",
"dispute_categories": [
"ITEM_NOT_RECEIVED",
"UNAUTHORIZED_TRANSACTION"
]
},
"invoice_id": "INV-1234567888",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/4K670967VH2547504",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/4K670967VH2547504/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/8G0042477K865063U",
"rel": "up",
"method": "GET"
}
],
"create_time": "2020-10-31T13:35:58Z",
"update_time": "2020-10-31T13:35:58Z"
}
]
}
}
],
"payer": {
"name": {
"given_name": "Sumit",
"surname": "Shukla"
},
"email_address": "testg32#gmail.com",
"payer_id": "VW87TYSM2GMZ4",
"address": {
"address_line_1": "10, east street",
"admin_area_2": "Mumbai",
"admin_area_1": "Maharashtra",
"postal_code": "400029",
"country_code": "NZ"
}
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/8G0042477K865063U",
"rel": "self",
"method": "GET"
}
]
}
After that you can redirect user to thank you page and update mobile app screen based on database values.
I have a class which is part of a school and this class has teachers and students, all of them has name and maybe has phone number , I want to get the full data for the classes
but firstly, could you advice me, what is the best for performance and maintaining from the following Dbs :
1st one
"schools":{
"school1":{
"class1":{
"name":"SC1",
"teachers":[{
"name":"T1"
}, {
"name":"T2"
}],
"students":[
{"name":"S1"},
{"name":"S2"}
]
}
}
.
.
.
.
.
.
.
}
and the 2nd
"school":{
"school1":{
"name":"SC1"
},
"school2":{
"name":"SC2"
}
},
"classes": {
"class1": {
"name": "C1"
},
"class2": {
"name": "C2"
}
},
"students": {
"student1": {
"name": "S1",
"phone":"123456789"
},
"student2": {
"name": "S2",
"phone":"123456789"
},
"student3": {
"name": "S3",
"phone":"123456789"
},
"student4": {
"name": "S4",
"phone":"123456789"
}
},
"teachers": {
"student1": {
"name": "T1",
"phone":"123456789"
},
"student2": {
"name": "T2",
"phone":"123456789"
},
"student3": {
"name": "T3",
"phone":"123456789"
},
"student4": {
"name": "T4",
"phone":"123456789"
}
},
"classes_enrollments": {
"class1": {
"teacher1": true,
"teacher3": true,
"student1": true,
"student2": true
},
"class2": {
"teacher2": true,
"teacher4": true,
"student3": true,
"student4": true
},
"class3": {
"teacher1": true,
"teacher2": true,
"student3": true,
"student4": true,
"student1": true,
"student2": true
}
},
"student_friends": {
"student1": {
"student2": true
},
"students2": {
"student1": true,
"student3": true
},
"students3": {
"student2": true
}
},
"teacher_friends": {
"teacher1": {
"teacher2": true
},
"teacher2": {
"teacher1": true,
"teacher3": true
},
"teacher3": {
"teacher2": true
}
}
and for the 2nd way how to get the full data for the class1: in which school and it's name and count of teachers and students and their names and phones
Thank you
I would mix those two.
For code simplicity and reading performance of individual class details, the 2nd scheme would indeed be messy. The 1st scheme would be better, but with some improvements.
Keep the teachers and students paths at root, just like in the 2nd scheme.
Add teacher_enrollments and student_enrollments path at root, to save the ids of the classes that each teacher/student is associated with.
Don't save class teachers and students as arrays inside classes, but use maps instead, similar to what you're saving in the root teachers and students path.
That way, when you edit a teacher from the root path, you can also get a list of all their associated classes (the ids) from the enrollments path, and do a multi-path update for these classes, to update the teacher/student details in each associated class.
If you have lots of data, you might want to maintain a separate path for class summaries, so that you can easily show a list of classes, without having to download the data for all included teachers and students (which would be present multiple times in all these classes).
When you delete a class, you would also want to do a multi-path update to delete all associated enrollments. If the total number of students and teachers is not too big, you can just delete the enrollments for ALL teacheres/students. If you have lots of teachers/students, you could keep your classes_enrollments path (but with intermediate teachers and students before the ids), so that you can make an update with only the required teacher/student ids. (it's actually a lot simpler. You already have the teacher/student IDs in the class info)
// How to delete a class in JavaScript.
// For Java, use updateChildren() instead of update(),
// and supply it with a HashMap instead of a plain object.
const classToDelete = { id: 'class1', teachers: ..., students: ..., school: ... };
const updateObject = {
['classes/'+classToDelete.id]: null },
['schools/'+classToDelete.school.id+'/classes/'+classToDelete.id]: null },
};
Object.keys(classToDelete.teachers).forEach(teacherId => {
updateObject['teachers/'+teacherId +'/classes/'+classToDelete.id] = null;
});
Object.keys(classToDelete.students).forEach(studentId=> {
updateObject['students/'+studentId+'/classes/'+classToDelete.id] = null;
});
dbRef.update(updateObject);
Example database structure (slightly different than instructed, but using the same concepts):
"schools": {
"school1": {
"id": "school1",
"name": "The best school",
"classes": {
"class1": {
"id": "class1",
"name": "The best class"
}
}
}
},
"classes": {
"class1": {
"id": "class1",
"name": "The best class",
"teachers": {
"teacher1": {
"id": "teacher1",
"name": "The best teacher",
"phone": "123"
}
},
"students": {
"student1": {
"id": "student1",
"name": "The best student",
"phone": "456"
}
},
"school": {
"id": "school1",
"name": "The best school"
}
}
},
"teachers": {
"teacher1": {
"id": "teacher1",
"name": "The best teacher",
"phone": "123",
"classes": {
"class1": {
"name": "The best class",
"school": {
"id": "school1",
"name": "The best school"
}
}
}
}
},
"students": {
"student1": {
"id": "student1",
"name": "The best student",
"phone": "456",
"classes": {
"class1": {
"name": "The best class",
"school": {
"id": "school1",
"name": "The best school"
}
}
}
}
}
Good luck!
I am creating an Android App.The App have a feature that retrieve Facebook posts using Graph API.
My Problem
My Problem is , the received JSON lacks the following fields:
Url for the images attached with the comments
Replies to the comments
Only No. of likes available. No Reactions list
For posts containing more than one images , full_picture fields contains link to only one image. Where is the link for other images ?
I used the /me/posts to get the posts.
Why I can't get the above details ?
Steps taken
I searched Stackoverflow but The answers only mentioned how to get images and replies for individual commment(by using comment id) , but no reference how to get it alongs with the JSON received from "/me/posts". (So , this is not a duplicate!!!!)
My Queries
Why I can't get the above details ?
What is the way to get comment's Images , replies,url for all images of the Parent post and Posts reactions in bundle.(that is along with the JSON of "/me/posts" without running /comment request for each and every comment?
My Code
Code the executes Graph Query
login_button.setReadPermissions(Arrays.asList(
"public_profile", "email", "user_birthday", "user_friends","user_posts", "user_status")); // Setting permissions
Bundle params = new Bundle();
params.putString("fields", "message,created_time,id,full_picture,status_type,source,comments.summary(true),likes.summary(true)");
params.putString("limit", "100");
new GraphRequest( loginResult.getAccessToken(), "/me/posts", params, HttpMethod.GET,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
/* handle the result */
try {
EditText postsText = (EditText) findViewById(R.id.postText);
String res = response.toString();
res = res.replaceAll("\\{Response:\\s*\\w*\\W*\\s*[0-9]*\\W*\\w*:", "");
res = res.replaceAll("\\,\\s*error:\\s*null\\W*\\s*","");
postsText.setText(res);
writeToFile(res,"response");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
).executeAsync();
}
#Override
public void onCancel() {
txtstatus.setText("Login canceled");
}
#Override
public void onError(FacebookException error) {
txtstatus.setText("Login failed"+error.getMessage());
}
});
JSON
{
"data": [
{
"message": "'A reader lives a thousand lives before he dies. The man who never reads lives only one.'\n- George RR Martin",
"created_time": "2018-01-28T12:17:54+0000",
"id": "113326729482474_113029916178822",
"full_picture": "https://scontent.xx.fbcdn.net/v/t1.0-9/26993527_113029839512163_7617357733573673432_n.jpg?oh=c617cf94e3cdd62320fde60e445f760e&oe=5B22BC72",
"status_type": "added_photos",
"likes": {
"data": [],
"summary": {
"total_count": 0,
"can_like": true,
"has_liked": true
}
},
"comments": {
"data": [
{
"created_time": "2018-01-28T12:23:04+0000",
"from": {
"name": "Ragesh D Antony",
"id": "1845099915531898"
},
"message": "Such a wonderful Quote ..",
"id": "113029916178822_113036856178128"
},
{
"created_time": "2018-01-28T13:59:22+0000",
"from": {
"name": "Vignesh Lakshmanen",
"id": "1558536637578045"
},
"message": "Superb",
"id": "113029916178822_113251916156622"
}
],
"paging": {
"cursors": {
"before": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVEV6TURNMk9EVTJNVGM0TVRJNE9qRTFNVGN4TkRJeE9EUT0ZD",
"after": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVEV6TWpVeE9URTJNVFUyTmpJeU9qRTFNVGN4TkRjNU5qST0ZD"
}
},
"summary": {
"order": "chronological",
"total_count": 2,
"can_comment": true
}
}
},
{
"message": "\"It's an insane world, but in it there's one sanity, the loyalty of old friends. Friends, we must believe in one another.\" \n\n- Ben Hur",
"created_time": "2018-01-28T12:14:27+0000",
"id": "113326729482474_113026646179149",
"status_type": "mobile_status_update",
"likes": {
"data": [
{
"id": "1845099915531898",
"name": "Ragesh D Antony"
},
{
"id": "1558536637578045",
"name": "Vignesh Lakshmanen"
}
],
"paging": {
"cursors": {
"before": "MTg0NTA5OTkxNTUzMTg5OAZDZD",
"after": "MTU1ODUzNjYzNzU3ODA0NQZDZD"
}
},
"summary": {
"total_count": 2,
"can_like": true,
"has_liked": false
}
},
"comments": {
"data": [
{
"created_time": "2018-01-28T12:24:40+0000",
"from": {
"name": "Ragesh D Antony",
"id": "1845099915531898"
},
"message": "I like Ben Hur very much",
"id": "113026646179149_113040629511084"
}
],
"paging": {
"cursors": {
"before": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVEV6TURRd05qSTVOVEV4TURnME9qRTFNVGN4TkRJeU9EQT0ZD",
"after": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVEV6TURRd05qSTVOVEV4TURnME9qRTFNVGN4TkRJeU9EQT0ZD"
}
},
"summary": {
"order": "chronological",
"total_count": 1,
"can_comment": true
}
}
}
],
"paging": {
"previous": "https://graph.facebook.com/v2.11/113326729482474/posts?fields=message,created_time,id,full_picture,status_type,source,comments.summary%28true%29,likes.summary%28true%29&limit=100&format=json&since=1517141874&access_token=EAATh9tg5DMIBANl59BIPExJRzwZAhedH6PSsV2ZAO9FvzFiGqAW3HKafH9b7Bb0gSKnQMJktzUhX2DZCB29BezRUfI2HOumZAYp6FFYwOBJA1ZCdaE4ZCNLXB1ctUZBaKwbp8lXlZBwZBLLCG25CnGAckZClJXZA5omRDFtVvnJFTkJpqigUmy22QNGFmF4CgfC6sWEuVin7mAI9WZCkKkNVzSEeDGDoitt7xeVFiHXCetKOVoLZAl3qyfrYj&__paging_token=enc_AdC03uweQZCRZBN6tZCzhAQ50BZCKzx5koYtAZBRUmgY94TKcCrj6owvzXw9lpoL4iBKJUkW1ZAz4MoZAZBBaGSLZAHTHsKuEst7gtKaQrsQoiZBx8sO2QjQZDZD&__previous=1",
"next": "https://graph.facebook.com/v2.11/113326729482474/posts?fields=message,created_time,id,full_picture,status_type,source,comments.summary%28true%29,likes.summary%28true%29&limit=100&format=json&access_token=EAATh9tg5DMIBANl59BIPExJRzwZAhedH6PSsV2ZAO9FvzFiGqAW3HKafH9b7Bb0gSKnQMJktzUhX2DZCB29BezRUfI2HOumZAYp6FFYwOBJA1ZCdaE4ZCNLXB1ctUZBaKwbp8lXlZBwZBLLCG25CnGAckZClJXZA5omRDFtVvnJFTkJpqigUmy22QNGFmF4CgfC6sWEuVin7mAI9WZCkKkNVzSEeDGDoitt7xeVFiHXCetKOVoLZAl3qyfrYj&until=1517140875&__paging_token=enc_AdC1r6ZBwBybSmO16DuZCEWGDbdqTeiKCbTsa7h6WDenaZBgB40Xbc0flGcwYqiYPFiEf9wEvuBSoEvbfyl25J0JlbyfhKA1ZBufZC5ZAJMqLMg6bAXgZDZD"
}
}
Well, regarding "reaction list", this is available only for the Page owner (starting from 2018 Febraury).
Read the Graph API docs:
https://developers.facebook.com/docs/graph-api/reference/v2.12/post
"For Posts on a Page:
Any valid access token can read posts on a public Page, but responses will not include User information.
A Page access token can read all Posts posted to or posted by that Page, and responses will include User information."
I'm currently developing basic social network Android app for sharing images. Already have PHP/mySQL back-end but thinking about migrating to Firebase because of some features that I like (e.g. security, fast read/write).
So, I have users, posts, followers, likes, comments (like every other social network nowadays).
Long story short, I want to know if I'm getting this right.
According to this Firebase documentation and its example I should include unique keys from some JSON trees to others like this (example from documentation):
// An index to track Ada's memberships
{
"users": {
"alovelace": {
"name": "Ada Lovelace",
// Index Ada's groups in her profile
"groups": {
// the value here doesn't matter, just that the key exists
"techpioneers": true,
"womentechmakers": true
}
},
...
},
"groups": {
"techpioneers": {
"name": "Historical Tech Pioneers",
"members": {
"alovelace": true,
"ghopper": true,
"eclarke": true
}
},
...
}
}
Does this mean that I will have to include keys from posts, comments, followers etc. to my users tree like this:
{
"users": {
"alovelace": {
"name": "Ada Lovelace",
"profileImage": "http://blabla.bla?xyzooqlL.png",
"about:" : "Exit light, enter night",
"country": "Neverland"
// Index Ada's posts in her profile
"posts": {
// the value here doesn't matter, just that the key exists
"post123": true,
"post234": true
},
// all comments this user wrote
"comments": {
"comment123": true
},
// all posts this user liked
"likes": {
"post123": true
},
"followers": {
"user123": true,
"user234": true
}
},
...
},
"posts": {
"post123": {
"image": "www.bla.bla/sadsadsa.png",
"description": "Hue hue hue",
"likes": {
"alovelace": true,
"ghopper": true,
"eclarke": true
},
"comments": {
"comment123": true,
}
},
"post234": {
"image": "www.bla.bla/233arweeq.png",
"description": "This is nice",
"likes": {
"eclarke": true
},
"comments": {
"comment234": true,
}
},
"comments": {
"comment123": {
"userId": "alovelace"
"text": "cool",
"date": "current"
}
},
...
}
}
Isn't it a little too much if I have for example 5000 followers, 2000 followings, 1500 post likes? When fetching user or any other object I will also fetch all its keys within that object. Imagine fetching 15 very active users with all this data.
If you have any suggestions how should I structure data, please let me know. Any kind of feedback will be useful.
Thanks.
I am attempting to query some hierarchical data in firebase. I'm having a little difficulty in figuring out how to query the following data structure:
{
"orgs": {
"-KBFXBBEyvgtfqMvU4pi": {
"name": "ACME 123",
"owner": "-K9IPqIUIuEFzLS0f_Pe",
"users": {
"-KBF_GhwTmXfR6Jce30t": {
"email": "userA#company.com",
"permission": "editor",
"userKey": "K99LV9cTjh1ovW1D5j2"
},
"-KBF_M533zzbUilGvAAW": {
"email": "userB#company.com",
"permission": "editor"
}
}
},
"-KBFaKlJ8tfqjBQjAZgq": {
"name": "ACME Alt LLC",
"owner": "-K9IPqIUIuEFzLS0f_ZZ",
"users": {
"-KBFbD4trt9nyeHPUQbn": {
"email": "userX#co.com",
"permission": "editor"
}
}
}
}
}
Specifically, I would like to find out if the email address "userB#company.com" exists. But this is a little confusing for me since I need to search through 2 levels (orgs and users).
After reading some more documentation it seems I really shouldn't be nesting my data like this. I'll be honest, it seems kind of contrary to do this when working with a JSON schema that that is hierarchical. Anyway, this is what I'm looking to do now:
{
"orgs": {
"-KBFXBBEyvgtfqMvU4pi": {
"name": "ACME 123",
"owner": "-K9IPqIUIuEFzLS0f_Pe"
}
},
"-KBFaKlJ8tfqjBQjAZgq": {
"name": "ACME Alt LLC",
"owner": "-K9IPqIUIuEFzLS0f_ZZ"
}
}
},
"orgMembership": {
"-KBFXBBEyvgtfq7h381h": {
"org": "-KBFXBBEyvgtfqMvU4pi",
"email": "userA#company.com",
"permission": "editor"
}
}
Then I can use the following query:
orgMRef.orderByChild("email").equalTo("userA#company.com").once("child_added", function(snapshot) {
console.log("found: " + snapshot.key());
});