How to read data from nested array in Firestore - java

I have the below structure in my Firestore and I want to read data and store it in ArrayList like I have "amountArrayList" which will read data from the "transactions" field in Firestore, I want to read all the "amount" fields from "transactions" field and make array list of it so that I can show it in list manner.
My code
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("transactions")) {
System.out.println(entry.getValue().toString());
}
}
Output
[{transactionType=Credit, amount=3000, dateToStr=17/12/2021, timeToStr=08:06:10, description=}, {transactionType=Credit, amount=2000, dateToStr=17/12/2021, timeToStr=08:06:50, description=}]

Since transactions is an array field, the value you get from entry.getValue() is a List of objects. Since each of these objects in the JSON has properties, they each will be a Map<String, Object> again in the Java code.
A simple way to print the amounts would be something like:
List transactions = document.get("transactions");
for (Object transaction: transactions) {
Map values = (Map)transaction;
System.out.println(values.get("amount")
}

While Frank van Puffelen's answer will work perfectly fine, there is a solution in which you can directly map the "transactions" array into a list of custom objects. Assuming that you have a class declaration that looks like this:
class User {
public String balance, email, firstname, lastname, password, username;
public List<Transaction> transactions;
public User(String balance, String email, String firstname, String lastname, String password, String username, List<Transaction> transactions) {
this.balance = balance;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.password = password;
this.username = username;
this.transactions = transactions;
}
}
And one that looks like this:
class Transaction {
public String amount, dateToStr, description, timeToStr, transactionType;
public Transaction(String amount, String dateToStr, String description, String timeToStr, String transactionType) {
this.amount = amount;
this.dateToStr = dateToStr;
this.description = description;
this.timeToStr = timeToStr;
this.transactionType = transactionType;
}
}
To get the list, it will be as simple as:
docRef.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
List<Transaction> transactions = document.toObject(User.class).transactions;
List<String> amountArrayList = new ArrayList<>();
for(Transaction transaction : transactions) {
String amount = transaction.amount;
amountArrayList.add(amount);
}
// Do what you need to do with your amountArrayList
}
}
});
You can read more info in the following article:
How to map an array of objects from Cloud Firestore to a List of objects?.

I found the best way to map the data from/to hashmap to send/retrieve it from FirebaseFirestore
First, you need to create an extension class to handle the mapping
fun <T> T.serializeToMap(): Map<String, Any> {
return convert()
}
inline fun <reified T> Map<String, Any>.toDataClass(): T = convert()
inline fun <A, reified B> A.convert(): B =
Gson().fromJson(Gson().toJson(this), object : TypeToken<B>() {}.type)
Don't forget to add Gson
implementation 'com.google.code.gson:gson:2.9.0'
Then, you can use these functions for mapping the result from firebase
if (task.isSuccessful) {
val list: MutableList<YourObject> = ArrayList()
for (document in task.result) {
list.add(document.data.toDataClass())
}
// do whatever you want with the list :)
} else {
// handle the error
}

Related

How to use a map in a java customobject for firestore

I have a Java customobject that I use in Firestore to set a product.
It looks partly like this:
package product.firebaseobjects;
import java.util.List;
import java.util.Map;
public class Product {
private List<String> productcodes;
private Map<String, String> altdescriptions;
private String description;
private Long amount;
private boolean hasimage;
public Product(){
}
public FBProduct(List<String> productcodes, Map<String, String> altdescriptions, String description, Long amount, boolean hasimage) {
this.productcodes = productcodes;
this.altdescriptions = altdescriptions;
this.description = description;
this.amount = amount;
this.hasimage = hasimage;
}
(getters & setters omitted)
Retrieving is done using
DocumentReference docRef = db.collection(PRODUCTS).document(id);
ApiFuture<DocumentSnapshot> future = docRef.get();
DocumentSnapshot document = null;
Product product = null;
try {
document = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (document.exists()) {
product = document.toObject(Product.class);
}
return product;
When I save this object using this code
List<string> productcodes = new ArrayList<>();
productcodes.add("productcode1");
productcodes.add("productcode2");
Map<String, String> alt = new HashMap<>();
alt.put("French","French description");
alt.put("German","German description");
String description = "Description";
Long amount = 1L;
boolean hasimage = false;
Product product = new Product(productcodes, alt, description, amount, hasimage);
ApiFuture<DocumentReference> future = db.collection(PRODUCTS).add(product);
all fields are saved to Firestore except for the field 'altdescriptions'. This field is not to be found. All examples in the docs use Map<String, Object> which i tried as wel but does not make a difference.
From searching I found solutions that use the update() method using dot notation, but then you are not using the customobject.
My question is, how to use a Map in a Firestore Java customobject. And if that is not possible, what is the preferred way of setting, updating and retrieving Maps for a customobject.

Spring Boot Rest Web Service fetching multiple parameters in Get Request

I am creating Spring Boot Web service and I have a Model Employee
public class Employee {
private String id;
private String name;
private String designation;
private int salary;
//Has Getters and Setters
}
I want to create a Get request which will fetching and filter the List of Employees based on the parameters given by user.
For example, if the user gives name of an employee and designation of employee, the get method should filter those result. For various combination of parameters it should work.
#Override
public List<Employee> getEmployees(Map<String, Object> parameters) {
if (parameters.size() == 0)
// code to return all employees;
List<Employee> selectedEmployees = new ArrayList<Employee>();
for(Employee currentEmployee: new ArrayList<Employee>(employee.values())) {
for(Map.Entry<String, Object> check: parameters.entrySet()) {
try {
if(check.getValue() instanceof Integer) {
int condition = (int) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if((int) check.getValue() == condition)
selectedEmployees.add(currentEmployee);
} else if (check.getValue() instanceof String) {
String condition = (String) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if (((String) check.getValue()).equals(condition))
selectedEmployees.add(currentEmployee);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
return selectedEmployees;
}
In order to avoid multiple if else cases I am filtering list based on String and Integer above.
I think I am making an error in the below code which sending request in Controller.
#RequestMapping(value={"/employees","/{id}/{name}/{designation}/{salary}"})
public List<Employee> getEmployeeByProperty(EmployeeRequestParameters requestParams){
//Map for storing parameters to filter the List
Map<String, Object> filterParams = new HashMap<>();
if(requestParams.getIdParam().isEmpty()) {
filterParams.put("id", Integer.parseInt(requestParams.getIdParam()));
}
if(!requestParams.getNameParam().isEmpty()) {
filterParams.put("name", requestParams.getNameParam());
}
if(!requestParams.getDesignationParam().isEmpty()) {
filterParams.put("designation", requestParams.getDesignationParam());
}
if(requestParams.getSalaryParam().isEmpty()) {
filterParams.put("salary", Integer.parseInt(requestParams.getSalaryParam()));
}
return EmployeeService.getEmployeesByProperty(filterParams);
}
If {id} field is not full, {name} or {designation} or {salary} to be null.For {name} or {designation} or {salary} to be full Because should be {id} full.
#GetMapping("/employees")
public List<Employee> getEmployeeByProperty(#RequestParam(value = "id", required=false) String id,
#RequestParam(value = "name", required=false) String name,
#RequestParam(value = "designation", required=false) String designation,
#RequestParam(value = "salary", required=false) int salary) {
//Your codes
}
Even if {id} is empty, you can use others.

Fetching list objects from single document using Cloud Firestore

I have list of object store in single document in Firestore. On my android side i am not able to fetch list of object and their inner data.
Here is code i am trying to fetch data
CollectionReference mCollectionReference = FirebaseFirestore.getInstance().collection("Categories");
mCollectionReference.document("Dinner Dishes").get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Collection<Object> objectMap = documentSnapshot.getData().values();
for(Object result:objectMap){
Sample obj = Sample.class.cast(result);
HashMap<String, String> pic = obj.getPic();
HashMap<String, String> name = obj.getName();
}
}
});
I need list of object i upload on Firestore in single document
My Model Class:
public class Sample {
private String name;
private String pic;
public Sample() {
}
public String getName() {
return name;
}
public String getPic() {
return pic;
}
}
You can convert it to a java object, if that is how you saved it?
ObjectType myObject = document.toObject(ObjectType.class);

How to make a list of maps with different datatypes in java?

I am not very good with Java, so please forgive me for my ignorance.
I am selecting from a table and looping through the result set to make a list that i can use to convert into json which should look like the following example.
{
"ContactId": "123",
"key": {
"type": "email",
"email": "emailAdress"
},
"address": "String",
"source": "String",
"revoked": true,
"text": "String"
}
I don't know how to put them into a list as there are different datatypes i need to put into hash maps.
Please note, in the exmaple above key is an object and i am trying to achieve the same thing in the list.
The ultimate goal is to covert the generated list into json.
I have created a few hashmaps but i don't think i am doing it the right way.
String Table = "TableName";
String sql = String.format("SELECT id_user, email FROM %s ", Table);
ResultSet res = dbConn.prepareStatement(sql).executeQuery();
Map<String, Map> keyObject = new HashMap<String, Map>();
Map<String, String> keyMap = new HashMap<String, String>();
Map<String, String> mainMap = new HashMap<String, String>();
List<Map<String, String>> contacts = new ArrayList<>();
int i = 0;
while(res.next()){
keyMap.put("type", "email");
keyMap.put("value", res.getString("email"));
keyObject.put("key", keyMap);
mainMap.put("tenant", res.getString("id_user"));
mainMap.put("purpose", "Marketing sendouts");
mainMap.put("legalBase", "Withdrawn");
contacts.add(i, map);
i++;
}
System.out.println(contacts);
Instead of using generic structures like List or Map, you'd be better off designing classes which model the structure you need. For instance, in the case above you'll probably have something like:
public class Contact {
private int contactId;
private ContactKey key;
private String address;
private String source;
private boolean revoked;
private String text;
// ....
}
Now this is a strongly typed structure which can be easily filled from the resultset. A tool like Jackson (or many others) can easily render it as JSON.
Create a Model Class and use it's getter and setter methods.
Eg.
public class Model {
    private String id;
    private String name;
//Use constructor
    public Model(String id, String name) {
        this.id = id;
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
// Now make your Map data Structure center code hereustom .
Hashmap<String,Model> Map = new Hashmap();
// Create a object of your custom Model datastructure and add data.
Model model = new Model("145","Jason");
Map.put("1st",model);
Note that all the data is store at "1st" key of Map.
Kudos.... Enjoy
If map is your preferred data structure, you can use the code below:
Map<String, Object> map = new HashMap<>();
map.put("ContactId", 123);
Map<String, Object> keyMap = new HashMap<>();
keyMap.put("type", "email");
keyMap.put("email", "emailAdress");
map.put("key", keyMap);
map.put("address", "aaaa");
ObjectMapper objectMapper = new ObjectMapper();
try {
String json = objectMapper.writer().withDefaultPrettyPrinter().writeValueAsString(map);
System.out.println(json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
I am assuming Jackson is the library you use for serialization.

How to store values using Jackson JSON to Java

I am having a really hard time understanding how to place a mapped valued into an array and how to iterate that array.
test.json
[
{
"Name": "Bob",
"Nationality": "",
"City": "Chicago",
"Phone" : "451232424234"
},
......continues with more objects
]
testTemplate.java
//imports
#JSONInclude(Json.Include.Non_NULL)
#JsonPropertyOrder({"Name,"Nationality","City","Phone"})
Public class testTemplate {
#JsonProperty("Name")
private String userName;
#JsonProperty("Nationality")
private String nation;
#JsonProperty("City")
private String city;
#JsonProperty("Phone")
private String phone;
#JsonProperty("Name")
public String getName (String userName) {
this.userName = userName;
}
#JsonProperty("Nationality")
public String nation (String nation) {
this.nation = nation;
}
#JsonProperty("City")
public String city (String city) {
this.city = city;
}
#JsonProperty("Phone")
public String phone (String phone) {
this.phone = phone;
}
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
testParse.java
Public Class testParse {
List<testParse> test;
ObjectMapper mapper;
protected void setUp() throws IOException {
mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT();
test = mapper.readValue(this.getClass().getResourcesAsStream("test.json"),
mapper.getTypeFactory().constructCollectionType(List.class, testParse.class));
I need to help first clarifying exactly what the code is doing, and how to put JSON properties (Name, Nationality,City,Phone) into Java.
My understanding is the testTemplate file create the strings in which the properties will be held, then the testParse file has the mapper feature (from Jackson) that reads through the json and puts all into "test" (as an array?)
My goal is in testParse, where if everything thing is in "test", then I read through that, and start to pull it out and place it into a folderList.
public static Map<String, String> userName throws IOException {
Map<String, String> folderList = new TreeMap<>();
//Don't know how, but iterate through "test"
LineIterator it = new LineIterator(//the method used to read the json file);
try {
while(it.hasNext()) {
String line = it.nextLine();
folderList.put(userName,nation) //can I also put city and phone at once as well or should I create another put: folderList.put(userName, city)
return folderList;
How does one do this? Is there a better way to put the properties of json into the folderList after using the jackson mapper?
Actually, testTemplate don't generate anything, what Jackson have done here is just get data from "test.json" as String, then using Reflection read the format of testTemplate.java. Based on template it've just have + setting you add to ObjectMapper object, Jackson will convert test.json to array of object Java.
P/S: you don't need to add annotation in both attributes and get function of POJO class, just do it in get function or attributes only, it's enough for Jackson.

Categories