I am working on a basic project where I want to implement search functionality on the user's collection. that functionality should use like query we have in sql.
Here is my code :
static Future<List> searchUser(String query) async {
final mongoDB = MongoDB();
final db = mongoDB.db;
var collection = db.collection("users");
var queryBuilder = where.eq(
'name',
query,
);
var cursor = await collection.find(queryBuilder).toList();
print(cursor);
return cursor;
}
I want to know how to implement such functionality.
Related
I am using Flutter and using sqflite package, and I am trying to create a query to get an integer value from a database but it is giving me an error:
Here is the code:
Future<int> getCurrencyRate(String symb) async{
Database db = await instance.database;
return await db.rawQuery("Select rate from Currencies where symb= '$symb'");
}
It is showing this error:
A value of type 'List<Map<String, Object?>>' can't be returned from the method 'getCurrencyRate' because it has a return type of 'Future'
How can I make the function return an int (which is the result of the query) instead of a list ?
Thanks
Future<double> getCurrencyRate(String symb) async{
final db = await instance.database;
final result = await db.rawQuery("SELECT rate FROM Currencies WHERE symb = '$symb'");
return result.isNotEmpty ? result.first["rate"] : 0.0;
}
Can someone help me to query the list of map object in the collection? Please find sample document below
see my sample document from firestore
In above the image I want to fetch the GROUP collection based on personId which is basically List type.
Searching for solution android. Please advise
Not sure whether its an optimal way of performing a query in Firestore but i only found this way. You can query a map but you will need both the personId as well as personName
Future<void> memberList() async {
List<Map> personList= new List<Map>();
Map<String, dynamic> personData = new Map<String,dynamic>();
personData ["personId"] = pid;
personData ['personName'] = pname;
personList.add(personData);
QuerySnapshot query;
query = await FirebaseFirestore.instance.collection('Group')
.where('groupMembers',arrayContainsAny: personList).get();
}
Let's take this example: I have a form, which has several sections, each having questions. Sideways, I have answers that are mapped to questions and they have another column that I want to filter on when querying:
So I have the following entities:
#Entity(tableName = "sections")
public class Section {
#PrimaryKey
public long id;
public String title;
}
#Entity(tableName = "questions")
public class Question {
#PrimaryKey
public long id;
public String title;
public long sectionId;
}
#Entity(tableName = "answers")
public class Answer {
#PrimaryKey
public long id;
public long questionId;
public int otherColumn;
}
In the section DAO I want to retrieve all of them.
Here's the POJO that I want filled by this query:
class SectionWithQuestions {
#Embedded
public Section section;
#Relation(parentColumn = "id", entityColumn = "sectionId", entity = Question.class)
public List<QuestionWithAnswer> questions;
public static class QuestionWithAnswer {
#Embedded
public Question question;
#Relation(parentColumn = "id", entityColumn = "questionId", entity = Answer.class)
List<Answer> answers;
}
}
In another application, the query would be:
SELECT s.*, q.*, a.*
FROM sections s
LEFT JOIN questions q ON q.sectionId = s.id
LEFT JOIN answers a ON a.questionId = q.id
WHERE s.id = :sectionId and a.otherColumn = :otherColumn
However in Room I have found out that if you want an object and their relations (like a user and its pets in the example), you only select the object, and the relations are queried in a second query. That would be:
#Query("SELECT * FROM sections WHERE id = :sectionId")
Then in the generated code there would be (pseudo code):
sql = "SELECT * FROM sections WHERE id = :sectionId" // what's inside #Query
cursor = query(sql)
int indexColumn1 = cursor.getColumnIndex(col1)
int indexColumn2
... etc
while (cursor.moveToNext) {
masterObject = new object()
masterObject.property1 = cursor.get(indexColumn1)
... etc
__fetchRelationshipXXXAsYYY(masterObject.relations) // fetch the child objects
}
and this __fetch XXX as YYY method is as follows:
sql = "SELECT field1, field2, ... FROM a WHERE foreignId IN (...)"
similar algo as previously: fetch column indices, and loop through the cursor
So basically it creates 2 queries: one for the master object and one for the relations. The 2nd query is automatically created and we have no control over it.
To get back to my problem where I want relations but also filter on the child column, I'm stuck:
in the 1st query I can't reference the otherColumn column because it doesn't exist
in the #Relation I can't either because the only properties of this annotation are the join column and entity definition
Is this possible in Room or do I have to make the subqueries myself?
Bonus question: why don't they join tables in a single query but create 2 queries instead? Is this for performance reasons?
Edit to clarify what I expected:
That's what I expected to write:
#Query("SELECT s.*, q.*, a.* " +
"FROM sections s " +
"LEFT JOIN questions q ON q.sectionId = s.id " +
"LEFT JOIN answers a ON a.questionId = q.id " +
"WHERE s.id = :sectionId and a.otherColumn = :additionalIntegerFilter")
SectionWithQuestionsAndAnswers fetchFullSectionData(long sectionId);
static class SectionWithQuestionsAndAnswers {
#Embedded Section section;
#Relation(parentColumn = "id", entityColumn = "sectionId", entity = Question.class)
List<QuestionWithAnswers> questions;
}
static class QuestionWithAnswers {
#Embedded Question question;
#Relation(parentColumn = "id", entityColumn = "questionId", entity = Answer.class)
Answer answer; // I already know that #Relation expects List<> or Set<> which is
// not useful if I know I have zero or one relation (ensured
// through unique keys)
}
That's pseudo code that I imagined to be implemented by Room as the generated code:
function fetchFullSectionData(long sectionId, long additionalIntegerFilter) {
query = prepare(sql); // from #Query
query.bindLong("sectionId", sectionId);
query.bindLong("additionalIntegerFilter", additionalIntegerFilter);
cursor = query.execute();
Section section = null;
long prevQuestionId = 0;
Question question = null;
while (cursor.hasNext()) {
if (section == null) {
section = new Section();
section.questions = new ArrayList<>();
section.field1 = cursor.get(col1); // etc for all fields
}
if (prevQuestionId != cursor.get(questionIdColId)) {
if (question != null) {
section.questions.add(question);
}
question = new Question();
question.fiedl1 = cursor.get(col1); // etc for all fields
prevQuestionId = question.id;
}
if (cursor.get(answerIdColId) != null) { // has answer
Answer answer = new Answer();
answer.field1 = cursor.get(col1); // etc for all fields
question.answer = answer;
}
}
if (section !=null && question != null) {
section.questions.add(question);
}
return section;
}
That's one query, and all my objects fetched.
I find Room Relations hard to work with, not very flexible and much of the work is done under the hood in a way that is hard to really be sure how.
In my projects, most of the time I just create presentation objects - objects dedicated for some UI presentation that can be filled with a custom select.
That way I have much more control over what I want to fetch from DB (i.e. what I really need), and I fill that into that custom presentation object.
I'm just pasting the information provided on the feature request I posted (see my comment on my question):
Hi there - we have recently released a new feature where relational query methods can be defined with Multimap return types. With this new feature, you should be able to achieve the results discussed in this thread. For more info on this new feature, you can check out the following resources:
Define relationships between objects: https://developer.android.com/training/data-storage/room/relationships
Relational Query Methods in ADS 2021: https://youtu.be/i5coKoVy1g4?t=344
The new MapInfo annotation: https://developer.android.com/reference/androidx/room/MapInfo
I know link-only answers aren't great, but I didn't have the opportunity to test this. If someone has a better answer, I'll accept it.
I found a better solution for this. Instead of aliasing all columns you can use #RawQuery annotation.
First of all, add a prefix for embedded table annotation using table name or its alias like #Embedded(prefix = "P.") or #Embedded(prefix = "Post."):
public class UserPost {
#Embedded
private User user;
#Embedded(prefix = "P.")
private Post post;
}
Then in your Dao, create a function to run a raw query, and create another function to run a raw query:
#Dao
public interface UserDao {
String USER_POST_QUERY = "SELECT U.*, P.* FROM User as U " +
"INNER JOIN Post as P ON U.id = P.userId " +
"WHERE P.status = 1";
#RawQuery
LiveData<List<UserPost>> rawQuery(SimpleSQLiteQuery query);
default LiveData<List<UserPost>> getAlertViolationsAsync() {
return rawQuery(new SimpleSQLiteQuery(USER_POST_QUERY));
}
}
I have more than one read query.
Query query = QueryOperations
.field("deleted").eq(false)
.select("title", "price", "district","anouncement_id")
.orderBy("announce_from", QueryOrder.Descending)
.skip(countIsLoaded) // counter
.top(5);
Another one is or ecc..
Query query = QueryOperations
.field("deleted").eq(false)
.orderBy("created", QueryOrder.Descending)
.skip(countIsLoaded) // counter
.top(5);
I will have to query using an Andriod Async Task.
Now i have more than one asyntask because i have not find a method to pass the query for Azure Mobile Service. This is the code currently i have
try {
MobileServiceTable<Foo> mToDoTable = MakeEasyApplication.mClient.getTable(Foo.class);
MobileServiceList<Foo> listAnnounce = mToDoTable.where()
.field("deleted").eq(false)
.select("title", "price", "announce_from", "district","anouncement_id")
.orderBy("announce_from", QueryOrder.Descending)
.skip(countIsLoaded)
.top(5)
.execute().get();
for (Foo foo: listAnnounce) {
publishProgress(foo);
}
} catch (Exception e) {
e.printStackTrace();
}
How i can pass the query param instead of having multiple Async Task?
#JoJo, per my experience, I think there are two ways to wrap multiple queries for a async task.
Wrap multiple queries with different query name defined into a function.
public Query getQuery(String qName) {
Query query = null;
switch(qName){
case "QN1":
query = QueryOperations
.field("deleted").eq(false)
.select("title", "price", "district","anouncement_id")
.orderBy("announce_from", QueryOrder.Descending)
.skip(countIsLoaded) // counter
.top(5);
break;
case "QN2":
query = QueryOperations
.field("deleted").eq(false)
.orderBy("created", QueryOrder.Descending)
.skip(countIsLoaded) // counter
.top(5);
break;
//......
default:
//......
}
return query;
}
//In async task
Query query = getQuery("<qName>");
MobileServiceTable<Foo> mToDoTable = MakeEasyApplication.mClient.getTable(Foo.class);
MobileServiceList<Foo> listAnnounce = mToDoTable.where().execute(query).get();
Using Custom APIs, you can define a custom API in the Mobile backend and call the custom API in Android client, then using the name of custom API as parameter instead of having multiple async task.
I just started learning about Cloud Endpoints from this tutorial by Google. The sample app provided in this tutorial defines Place as a JPA entity that has a GeoPt field for storing its location in the the App-Engine backend app which can be accessed by an android client via Google Cloud Endpoints.
I want to modify the PlaceEndPoint class in this sample app to return the list of only those places stored in the datastore that are nearby the user of the Android app instead of listing all the places in the datastore. By nearby, I mean a list of those places that lie in around 30 km radius sorted by the distance from the user. I would later need to apply more filters to these results by the type of places the user wants to see.
To do this I would probably have to:
1. Pass the user's location from the android client to the App-Engine backend
2. Tweak the function listPlace() in the PlaceEndpoint class of the backend app to return places near the user
But I'm not familiar enough with App Engine and Endpoints to figure out how to go about it. Please give me any hint or direction that would be helpful. Thanks so much in anticipation!!
Here is the code for the listPlace method in the PlaceEndpoint class as contained in the Google's sample app:
#Api(name = "placeendpoint", namespace = #ApiNamespace(ownerDomain = "google.com", ownerName = "google.com", packagePath = "samplesolutions.mobileassistant"))
public class PlaceEndpoint {
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*
* #return A CollectionResponse class containing the list of all entities
* persisted and a cursor to the next page.
*/
#SuppressWarnings({ "unchecked", "unused" })
#ApiMethod(name = "listPlace")
public CollectionResponse<Place> listPlace(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
EntityManager mgr = null;
Cursor cursor = null;
List<Place> execute = null;
try {
mgr = getEntityManager();
Query query = mgr.createQuery("select from Place as Place");
if (cursorString != null && cursorString != "") {
cursor = Cursor.fromWebSafeString(cursorString);
query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
}
if (limit != null) {
query.setFirstResult(0);
query.setMaxResults(limit);
}
execute = (List<Place>) query.getResultList();
cursor = JPACursorHelper.getCursor(execute);
if (cursor != null)
cursorString = cursor.toWebSafeString();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (Place obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<Place> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}