Is it possible to use Algolia query in FirestoreRecyclerOptions?

To allow my user performing more complex search, I'm working with Algolia.

com.algolia.search.saas.Query algolia_query =
                    new com.algolia.search.saas.Query(mLastQuery)
                    .setAttributesToRetrieve("content")
                    .setAttributesToRetrieve("category")
                    .setHitsPerPage(10);
            index.searchAsync(algolia_query, new CompletionHandler() {
                @Override
                public void requestCompleted(JSONObject jsonObject, AlgoliaException e) {
                    Log.d("algolia", jsonObject.toString());
                }
            });

I would like to convert this jsonObject into something compatible with FirestoreRecyclerOptions to be able to use FirestoreRecyclerAdapter

Thank you !


For a better understanding, I'll try to explain this with an example. Let's assume we have a FirebaseFirestore object that points to the root reference of the database and a CollectionReference object that points to a collection named products. And for that we can use the following two lines of code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference productsRef = rootRef.collection("products");

Let's aslo assume we have a Cloud Firestore database that looks like this:

Firestore-root
     |
     --- products
            |
            --- productIdOne
            |      |
            |      --- productName: "Milk"
            |
            --- productIdTwo
                   |
                   --- productName: "Soy Milk"
            |
            --- productIdThree
                   |
                   --- productName: "Bacon"

To achieve this structure, let's add these products to the database and also the corresponding indexes, using the code below:

Map<String, Object> mapOne = new HashMap<>();
mapOne.put("productName", "Milk");
Map<String, Object> mapTwo = new HashMap<>();
mapTwo.put("productName", "Soy Milk");
Map<String, Object> mapThree = new HashMap<>();
mapThree.put("productName", "Bacon");

WriteBatch writeBatch = rootRef.batch();
writeBatch.set(productsRef.document(), mapOne);
writeBatch.set(productsRef.document(), mapTwo);
writeBatch.set(productsRef.document(), mapThree);
writeBatch.commit();

Client client = new Client(YourApplicationID, YourAPIKey);
Index index = client.getIndex("products");

List<JSONObject> productList = new ArrayList<>();
productList.add(new JSONObject(mapOne));
productList.add(new JSONObject(mapTwo));
productList.add(new JSONObject(mapThree));
index.addObjectsAsync(new JSONArray(productList), null);

Let's also assume we have 2 views in out layout file, an EditText and a ListView.

EditText editText = findViewById(R.id.edit_text);
ListView listView = findViewById(R.id.list_view);

To actually display those products in our ListView, let's use the following code:

productsRef.get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    List<String> list = new ArrayList<>();
                    for (DocumentSnapshot document : task.getResult()) {
                        list.add(document.getString("productName"));
                    }
                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, list);
                    listView.setAdapter(arrayAdapter);
                } else {
                    Log.d(TAG, "Error getting documents: ", task.getException());
                }
            }
        });

In order to filter the products according to the text that we type in our EditText, we need to add a TextChangedListener like this:

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void afterTextChanged(Editable editable) {
        Query query = new Query(editable.toString())
                .setAttributesToRetrieve("productName")
                .setHitsPerPage(50);
        index.searchAsync(query, new CompletionHandler() {
            @Override
            public void requestCompleted(JSONObject content, AlgoliaException error) {
                try {
                    JSONArray hits = content.getJSONArray("hits");
                    List<String> list = new ArrayList<>();
                    for (int i = 0; i < hits.length(); i++) {
                        JSONObject jsonObject = hits.getJSONObject(i);
                        String productName = jsonObject.getString("productName");
                        list.add(productName);
                    }
                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, list);
                    listView.setAdapter(arrayAdapter);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }
});

So in order to make it work, we have created a new adapter object. This means that for every character that we type in the EditText, we create a new adapter and we populate this adapter with the results that are coming from the database. And to answer your question, in order to achieve what you want, you don't have to change the JSONObject, you have create a new query object that should be passed to the setQuery() method that is called on the FirestoreRecyclerOptions object. I just gave you a simpler example to understand the flow. For more information, I also recommend you see this video.


There is no connection between FirebaseUI and Algolia. If you want to show search results from Algolia, you'll have to build an adapter yourself.

You could consider using FirebaseUI's FirebaseIndexedArray for inspiration. But fair warning: both its internals, and the modifications needed, are quite involved.