Consider the following JSON format in Firebase database -
"root":
{
"question":
{
"1":
{
"category":"A",
"replies":0
},
"2":
{
"category":"B",
"replies":1
},
"3":
{
"category":"B",
"replies":0
},
"4":
{
"category":"C",
"replies":2
}
}
}
For getting all questions with replies = 0, I do,
Query query = rootReference.child("question").orderByChild("replies").equalTo(0);
which works perfectly.
But what should I do if I want those questions with replies not equal to 0 ?
Reading the documentation, I see no notEqualTo() method or any other way to "negate" a query. However, since you're already calling .orderByChild("replies"), you could perhaps use this:
Query query = rootReference.child("question").orderByChild("replies").startAt(1);
Firebase currently supports only positive operations, not the negation.
so you may want to retrieve all the data and then filter it locally.
Here is full answer
Actually Firebase doesn't provide any method to exclude some results like you are seeking here.
However, you can modify your JSON like this & then use following query:
// add a different key for all replies = 0, & another different key for non-zero replies
"root":
{
"question":
{
"1":
{
"category":"A",
"replies":0,
"key2":"someOtherKey"
},
"2":
{
"category":"B",
"replies":1,
"key1":true
},
"3":
{
"category":"B",
"replies":0,
"key2":"someOtherKey"
},
"4":
{
"category":"C",
"replies":2,
"key1":true
}
}
}
// now you can use this query to get all non-zero-replies results
// it will give you child 2, 4
Query query = rootReference.child("question").orderByChild("key1").equalTo(true);
// to get all zero-replies childs, use this
Query query = rootReference.child("question").orderByChild("key1").equalTo(null);
Related
I'm very new to NoSql databases, and I just want to ask you an easy question about the use of sembast! I'm developing a very simple app with flutter, and I want to get the object inside the array "list" with the "name" equal to 1.
{
"id": 12345,
"list": [{
"name": 1,
"element": [{
"nameItem": "a"
}, {
"nameItem": "b"
}]
}, {
"name": 2,
"element": []
}, {
"name": 3,
"element": []
}]
}
So I want to make a query that retrieves me this information:
{
"name": 1,
"element": [{
"nameItem": "a"
}, {
"nameItem": "b"
}]
}
I've written this code, but it doesn't work: I don't understand how to make a query with a subtag as a key in the json tree.
Future<List<ElementList>> getElementFromList(int name) async{
final finder = Finder(filter: Filter.equals("name", name));
final recordSnapshot = await _elementList.find(await _db, finder: finder);
return recordSnapshot.map((snapshot){
final elementObj = ElementList.fromJson(snapshot.value);
return elementObj;
}).toList();
}
this returns me []. How can I solve the problem?
Thank you in advance!
Sembast queries allow to filter records, not part of a record. If the object you mention is a whole record, you can:
use custom filter to perform the lookup yourself for each record in the database (checking each item in the list field`)
when a record is retrieved, extract the item (doing a similar Map/List manipulation)
See an issue with a complex filtering
I am trying to make some kind of comments using Firebase for Android.
Just have one question, are there any way to add new items to array?
For example, if I have such kind of object
If I am trying to push, it will convert it to map
And I don't want to overwrite this object each time, because I will have multiuser support and it will fail at some point.
And I am trying to do it as a List to do not create DataTransferObjects for my models, and to support auto parsing using firebase.
Thanks! If there will be no ideas will go with creating Maps, actually.
My ObjectModel:
public class Company implements Parcelable {
private String id;
private String name;
private String description;
private List<Comment> comments;
}
Code for pushing item:
final DatabaseReference ref = companiesRef.child(companyId).child(NODE_COMMENTS).push();
return Single.create(e -> ref.setValue(comment)
.addOnCompleteListener(task -> {
e.onSuccess(task.isSuccessful());
}));
This is how it works, look at the example below I have stored "0" as my first commentID and "1" as my second commentID. As you can see, I stored the lastCommentID as the commentID for the last comment in the lists.
{
"comments": {
"0": {
"text": "mycomment",
"time": "142351516"
},
"1": {
"text": "secondcomment",
"time": "153426564"
}
}
"lastCommentId": "1"
}
So whenever you want to add new comment to the firebase you have to retrieve the lastCommentID first as a string and convert it to integer(E.g. 1) then add 1 to the value(E.g. 2) so that when you save the next comment it won't override the previous version.
Note that you have replace lastCommentID each time you add comment to the database.
{
"comments": {
"0": {
"text": "mycomment",
"time": "142351516"
},
"1": {
"text": "secondcomment",
"time": "153426564"
},
"2": {
"text": "thirdcomment",
"time": "153426564"
}
}
"lastCommentId": "2"
}
You do not need to have a Model Class to write in Firebase, you can parse a JSON to Java Objects dinamically with Jackson and push it into Firebase.
You can parse a JSON as Java Objects with Jackson
. For example you can obtain: Object, List, Hashmap, Integer, String,
etc. without POJO classes.
To see more please visit this answer
I am not that skilled with Retrofit library and I ran into a problem that i don't know how to handle without restructuring the whole project.
Basically, i have two responses that are very similar, but my code only handles one response.
Here are the responses and what i did, so tell me if there is any way to do this...
{
"cv":[
{
"id":46,
"name":"Ciriculum Vitae",
"description":"Lorem ipsum description is the best description one can write down",
"file":"1482915089-test-test-cv1.pdf",
"file_url":"http://xxxyy/file/46/1482915089-test-test-cv1.pdf",
"type":"cv"
},
...
],
"diploma":[
{
"id":52,
"name":"dasdasdasdsa",
"description":"Random description",
"institution_name":"hello",
"completed_date":"12.12.2016.",
"file":"1482918005-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/52/1482918005-test-test-dasdasdasdsa.pdf",
"type":"diploma"
}
],
...
"certification":[
{
"id":50,
"name":"Certificate of Greatness",
"description":"I have been great at many things so everybody diecided to give me a certificate for it.",
"institution_name":"Certification 3",
"validation_date":"10.06.2017.",
"file":"1482917772-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/50/1482917772-test-test-dasdasdasdsa.pdf",
"type":"certification"
}
],
...
}
Okay this is just a sample, but you can clearly see that these are some documents that have their types. There are 17 types of documents each with different fields.
Logically, I've created 17 different models cv model, diploma model, etc...
The problem arises later in the project when i want to fetch documents that are related to a single candidate, the response then is like so:
Response2
"documents": [
{
"id": 46,
"name": "Ciriculum Vitae",
"type": "cv",
"description": "Lorem ipsum description is the best description one can write down",
"file": "1482915089-test-test-cv1.pdf",
"file_url": "http://xxxyy/file/46/1482915089-test-test-cv1.pdf"
},
{
"id":52,
"name":"dasdasdasdsa",
"description":"Random description",
"institution_name":"hello",
"completed_date":"12.12.2016.",
"file":"1482918005-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/52/1482918005-test-test-dasdasdasdsa.pdf",
"type":"diploma"
},
{
"id": 50,
"name": "Certificate of Greatness",
"type": "certification",
"description": "I have been great at many things so everybody diecided to give me a certificate for it.",
"file": "1482917772-test-test-dasdasdasdsa.pdf",
"file_url": "http://xxxyy/file/50/1482917772-test-test-dasdasdasdsa.pdf"
}
]
}
Now obviously the field 'type' is the type of object that needs to be created. But so far i don't know how to make my models fit into this 2nd response.
What should i do here, guys?
In case you're wondering what my code looks like, here it is...
#SerializedName("cv")
#Expose
private List<Cv> cv = null;
...
#SerializedName("diploma")
#Expose
private List<Diploma> diploma = null;
...
#SerializedName("certification")
#Expose
private List<Certification> certification = null;
EDIT
Actually what i wanted to do is create object dependent on the 'type' parameter and fill it with info i get from the response.
How will i go about doing this?
I found a lot of tutorials here, how to parse JSON Data of an JSON Array.
But my JSON File is a little bit complicate (for me). It has the following structure:
JSON File (excerpt)
{
"data": {
"schedule_id": {
"12": {
"name": "CP",
"d_id": [
"7"
]
},
"17": {
"name": "WT",
"d_id": [
"88",
"14"
]
}
}
}
}
Java Code (excerpt)
Info: I've parsed the json into "json" using HTTP GET in another Activity.
JSONObject dataJsonData = json.getJSONObject("data").getJSONObject("schedule_id");
Now I would parse through the ids using a "for"-loop:
ArrayList<String> parsedNameList = new ArrayList<String>();
for (int i = 0; i < idontknow; i++) {
String s = new Integer(i).toString();
parsedNameList.add(dateJsonData.getJSONObject(i).getString("name"));
}
This would add each value of "name" to the ArrayList.
But there are 2 problems:
1. The "schedule_id"s are messed up and incomplete. For example, there is no id "0" and, like in given json, the ids "13, 14, 15, 16" are missing.
2. The "schedule_id"s will be changed every day and will be mixed.
So I don't think, that I can use the predefined integer "i" because some integers aren't a "schedule_id". I could use this loop and would ignore empty entries in the ArrayList, but the JSON contains more than 200 ids - I think it would be more efficient, if there is another way to parse through this json.
I found some informations of the getJSONArray method, but the "d_id"s are Arrays - not the "schedule_ids".
Does anyone has an idea? Is there maybe a placeholder for the parameter of the getString method?
PS: Excuse my english, I'm from germany :)
I think this should work
Iterator keys = dataJsonData.keys();
while(keys.hasNext()) {
// loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
// get the value of the dynamic key
String currentDynamicValue = dataJsonData .getString(currentDynamicKey);
parsedJsonList.add(currentDynamicValue );
}
Source: How to parse a dynamic JSON key in a Nested JSON result?
According to your context, it is better to change the json structure,if you have access to web service.
Request for json structure to be like this,
{
"data":{
"schedule":[
{
"id":12,
"name":"CP",
"d_id":[
"7"
]
},
{
"id":12,
"name":"CP",
"d_id":[
"7",
"88"
]
},
{
"id":200,
"name":"AT",
"d_id":[
"7",
"88"
]
}
]
}
}
Otherwise too much iteration can slow down you CPU.
Coming from SQL background and watching tutorials, I am trying to do a model in Firestore to understand how things work. I basically wants model a situation where user has multiple lists and every list has his friends ( to display names of friends). Does the below make sense?
Users
"john#xyz.com"
-Name: John Smith
"celina#xyz.com"
- Name: Celina West
"dan#xyz.com"
- Name: Dan Nelson
Lists
"john#xyz.com"
List_Titles
"List 1"
- <AutoGenId>: Celina West
- <AutoGenId>: Dan Nelson
anything with "-" is a field, anything with bracket it Document and anything without prefixes is collection.
One issue I find here, is that lets say a user updates his/her name. Then I have to go not to only Users Collection but through every subcollection List to look for that person and update name. I thought about using email ID instead of name but then that goes against the "structure the nosql db as you view it" way. Plus then everytime I have to hit the Users tables in a seperate call for every Id to query the name.
Is my assumption correct?
Thanks
Snake, there is no perfect database structure. You need to model your database so you can query very easily later, when you need to do CRUD operations. In one of my tutorials, I have explained step by step how can we structure a Firestore database which holds users, lists and products.
Please see the below database structure that can help achieve what you want.
{
"users": {
"appfirstuser#gmail.com": {
"tokenId": "eGVzwv7Y...",
"userEmail": "appfirstuser#gmail.com",
"userName": "First User"
},
"appseconduser#gmail,com": {
"tokenId": "cc8Uhriu...",
"userEmail": "appseconduser#gmail.com",
"userName": "Second User"
}
},
"shoppingLists": {
"appfirstuser#gmail.com": {
"userShoppingLists": {
"3Oe37QdcHXSohL2dnNlX": {
"createdBy": "First User",
"date": "February 3, 2018 at 2:56:31 PM UTC+2",
"shoppingListId": "3Oe37QdcHXSohL2dnNlX",
"shoppingListName": "Pharmacy"
},
" WovuleVbTZdql68gXk84": {
"createdBy": "First User",
"date": "February 3, 2018 at 2:56:20 PM UTC+2",
"shoppingListId": "WovuleVbTZdql68gXk84",
"shoppingListName": "Grocery"
}
}
}
},
"products": {
"WovuleVbTZdql68gXk84": {
"shoppingListProducts": {
"8vinaHJyjG4JqFH33YE7": {
"productId": "8vinaHJyjG4JqFH33YE7",
"productName": "Milk"
},
"JALygtedMHWQcdEoSnPM": {
"productId": "JALygtedMHWQcdEoSnPM",
"productName": "Eggs"
},
"WFkJMWZSnhJU9iwGeoOi": {
"productId": "WFkJMWZSnhJU9iwGeoOi",
"productName": "Bacon"
}
}
}
}
}
Using a database structure that looks like this, you'll be abte to create, read, update and delete records very easily.