I need to check if a field contains specific String, and if it does - delete the entire row by id.
This code doesn't working:
Query<Bet> query = ofy().load().type(Movie.class);
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
ofy().delete().type(Movie.class).id(m.getId()).now();
}
}
}
In this case (deleting all movies with Brad Pitt in it as an actor) you could delete the entity like this:
Query<Movie> query = ofy().load().type(User.class);
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
ofy().delete().entity(m).now();
}
}
}
Not that i delete with delete().entity(...). Another option would be to delete by key like so delete().key(Key.create(Movie.class, idToRemove). The former does something quite similar but since you have the whole entity you don't need to complicate things. Also if you delete with entity(...) it will work when the entity has a #Parent whereas if you delete by key you'd have to additionally specify the ancestor in Key.create(ancestorKey, Movie.class, idToRemove).
I usually do multiple deletes like this:
Query<Movie> query = ofy().load().type(User.class);
List<Movie> toDelete = new ArrayList<>();
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
toDelete.add(m);
}
}
}
ofy().delete().entities(toDelete).now();
Performing database operations in a loop is bad style and should be avoided if possible.
One more thing:
If you must delete an entity by id the line would look like this:
ofy().delete().type(Movie.class).id(idToDelete);
However, as i hinted at before, if your Movie class has a parent this will not work because you must always specify the whole key, thus with ancestor the line would look like this:
Key<MyParentClass> parent = Key.create(MyParentClass.class, myParentId);
ofy().delete().type(Movie.class).parent(parent).id(idToDelete);
which is equivalent to
ofy().delete().key(Key.create(Key.create(MyParentClass.class, myParentId), Movie.class, idToDelete));
Related
I am getting values from Firebase. But the problem occur when i try to add values in array previous values get repeated. Can anyone tell me how can i put values in Array . i want to show those values in recyclerview.
Code :
bookCollection
.get().addOnSuccessListener {
booksSnapshot->
if (!booksSnapshot.isEmpty){
var booksArray = arrayListOf<Book>()
for (bookSnapshot in booksSnapshot.documents){
val hashmap = bookSnapshot.data
hashmap?.put("id", bookSnapshot.id)
bookCollection.document(bookSnapshot.id).collection("pages")
.get().addOnSuccessListener {
pagesSnapshot->
hashmap?.put("page_count", pagesSnapshot.documents.size)
val bookData = Gson().toJson(hashmap)
val book = Gson().fromJson<Book>(bookData, Book::class.java)
booksArray.add(book)
}
}
}
}
Log for array :
E/books: [co.myapp.myapplication.Book#d6f7f62]
E/books: [co.myapp.myapplication.Book#d6f7f62, co.syntags.myapplication.Book#93c49b0]
Thanks in advance
You have to clear your ForEach loop booksArray before adding new values.
Because when you are adding new values that is added as the next items in your array.
Use booksArray.clear() Before adding new values where you are using booksArray.add(book)
Replace this var booksArray = arrayListOf<Book>() With var booksArray = ArrayList<Book>()
in main class (List add) :-
(Yourlistname).add(new yourpojoname(your value));
in PoJo class :-
create constructor :-
--> public constructorName(String s) { (Your value) = s; }
note :- yourpojoname == constructorName
What I want to do is finding all records that match some id and sorted by a name. The data looks something like:
{
type:"receiving",
saleName:"Harshitha",
penId:"7aac88118420858d62f5ea55e22"
}
{
type:"receiving",
saleName:"Tom",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
{
type:"receiving",
saleName:"James",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
I want to get documents with some specific penID sorted by saleName.
Ex:- I want to get documents with this penId ‘81fb1a79526f4e2bdc77aa7d73d’ and sort them by saleName. Like this order:-
{
type:"receiving",
saleName:"James",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
{
type:"receiving",
saleName:"Tom",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
My view like this,
View view = database.getView("receiving_view");
if (view.getMap() == null) {
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if (document.get("type").equals("receiving") ) {
List<Object> keys = new ArrayList<Object>();
keys.add(document.get("penId"));
keys.add(document.get("saleName"));
emitter.emit(keys, document);
}
}
}, "1.1");
}
return view;
Then I tried to get data like this,
View view = getView("receiving_view");
Query query = view.createQuery();
List<Object> keys = new ArrayList<Object>();
keys.add("81fb1a79526f4e2bdc77aa7d73d");
List<Object> allKeys = new ArrayList<Object>();
allKeys.add(keys);
query.setKeys(allKeys);
query.run();
It’s not working because I passed one key, but their are two keys in the view… But I can’t pass the ‘saleName’ as a key because I want only to sort by ‘saleName’. What is the best way to do this?
Finally I found the solution. I don’t want to use setKeys here, I should use range of keys, not a specific set of keys.
I set startKey to [penID] and endKey to [penID, {}]. The empty map sorts after any other value, so this key range includes all keys that start with penID. I change my data getting method. Now this is what it is looks like,
View view = getView("receiving_view");
Query query = view.createQuery();
query.setStartKey(Arrays.asList("81fb1a79526f4e2bdc77aa7d73d"));
query.setEndKey(Arrays.asList("81fb1a79526f4e2bdc77aa7d73d", new HashMap<String, Object>()));
query.run();
I developed this app for my senior project and used SQLite and stored everything locally. I want to convert everything to Firebase now but there aren't that many tutorials out there, at least for what I'm trying to do. My question is how would I go about converting a query like the below to a Firebase database query?
public ArrayList<String> getAllBeautyItems() {
itemsList.clear();
dbHelper.getReadableDatabase();
ArrayList<String> itemNames = new ArrayList<>();
String[] tableColumns = new String[]{
Constants.ITEM_NAME, Constants.CATEGORY
};
String whereClause = Constants.CATEGORY + "=?";
String[] whereArgs = new String[]{
"beauty"
};
Cursor result = db.query(Constants.ITEMS_TABLE_NAME, tableColumns, whereClause, whereArgs,
null, null, null, null);
if (result.moveToFirst()) {
do {
itemNames.add(result.getString(result.getColumnIndex(Constants.ITEM_NAME)));
} while (result.moveToNext());
}
result.close();
return itemNames;
}
and then in a fragment I'm calling a setName, so how do I get the result of that query and apply it like in the below?
private ArrayList<Items> refreshData() {
dbItems.clear();
final ArrayList<String> itemNames = adapter.getAllBeautyItems();
ArrayList<String> itemImages = adapter.getAllBeautyImages();
ArrayList<Integer> itemPrices = adapter.getAllBeautyPrices();
ArrayList<String> itemDescriptions = adapter.getAllBeautyDescriptions();
ArrayList<String> itemLocations = adapter.getAllBeautyLocations();
ArrayList<String> itemLats = adapter.getAllBeautyLats();
int totalItems = adapter.getTotalBeautyItems();
String formattedItems = Utils.formatNumber(totalItems);
totalItemsText.setText("Total Items: " + formattedItems);
ArrayList<Items> items = new ArrayList<>();
for (int i = 0; i < itemNames.size(); i++) {
Items item = new Items();
item.setItemName(itemNames.get(i));
item.setItemImage(itemImages.get(i));
item.setItemPrice(itemPrices.get(i));
item.setItemDescription(itemDescriptions.get(i));
item.setItemLocation(itemLocations.get(i));
item.setLatLocation(itemLats.get(i));
items.add(item);
}
return items;
}
First of all, I wanna recommend you this: https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html
It's a tutorial that show you how yo make typical SQL queries in Firebase, BUT, like the owner says:
While this post still contains some useful and relevant information, we have released advanced query functionality which solves a lot of the problems this post discusses.
So, now, I will tell you the basic query that may solve your problem.
As I see, you have a table about Items, and you are doing a SELECT where that item's Category is beauty.
I will assume that you already know how data is stored in Firebase, so I'm not making us lose time explaining to you about the database tree.
Reading
You will need something like:
Query query = FirebaseDatabase.getInstance().getReference()
.child("items")
.orderByChild("Category")
.equalTo("beauty");
This, after attaching the listener to it, will search in the items tree, those items where the value of its category child, is beauty. The logic here is:
FirebaseDatabase.getInstance().getReference() -> Go to the main node
.child("items") -> Go to the Items node
.orderByChild("Category") -> Order them by its Category child
.equalTo("beauty") -> Look only at those with the "beauty" value
You will always need to do an orderBy*() to append an equalTo() and mimic the WHERE clause.
And, in your listener you will have something like:
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
List<Item> list = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Item item = snapshot.getValue(Item.class);
list.add(item);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//
}
};
query.addValueEventListener(eventListener);
And, since all Firebase connections are async, you will need a calback method to return the list after the for.
Writing
Now, for the upload, you will need a DatabaseReference, instead of a Query, like:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("items");
And all you need to do is:
ref.push().setValue(item); -> For a random ID
ref.child(key).setValue(item); -> For an specific ID (key)
I have been trying to OR two condition on two different fields of a table. while individual condition works fine, but when I try to use it both, it doesn't work.
Here is my code :
ParseQuery<NewExamAlert> query = ABC.getQuery();
query.whereContainedIn("category", Arrays.asList(arr)); //here arr is array of different category
query.whereContainedIn("subCategory", Arrays.asList(arr1));//here arr1 is array of different subcategory
query.findInBackground(new FindCallback<ABC>() {
public void done(List<ABC> list, ParseException exp) {
//My Logic
}
}
Please let me know, what am I missing ?
You'll need to explicitly "or" them:
List<ParseQuery<NewExamAlert>> queries = new ArrayList<ParseQuery<NewExamAlert>>();
queries.add( ParseQuery<NewExamAlert> query1 = ABC.getQuery()
.whereContainedIn("category", Arrays.asList(arr)) );
queries.add( ParseQuery<NewExamAlert> query2 = ABC.getQuery()
.whereContainedIn("subCategory", Arrays.asList(arr1)) );
ParseQuery<NewExamAlert> orQuery = ParseQuery.or( queries );
orQuery.findInBackground(new FindCallback<ABC>() {
public void done(List<ABC> list, ParseException exp) {
//Your Logic
}
}
Currently working on an app that takes results from a search, parses the JSON object returned, and then adds the resulting pieces into a few ArrayLists within a class created called VenueList.
Here is the method that receives the results from the service and parses the JSON:
private static List<String> getResultsFromJson(String json) {
ArrayList<String> resultList = new ArrayList<String>();
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
resultList.add(result.getString("text"));
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return resultList;
}
What results of this becomes a List variable call mResults (to clarify: mResults = getResultsFromJson(restResult);. That is then used, among other places, in the following loop that puts the results into an ArrayAdapter that is used for displaying them in a ListFragment:
for (String result : mResults) {
VenueList.addVenue(result, "HELLO WORLD");
adapter.add(result);
}
I also add the result to a class called VenueList that manages the results and makes them accessible for multiple views. It essentially just holds multiple ArrayLists that hold different types of details for each venue returned in the search. The method I use to add a venue to VenueList is below (and you can see it used in the for loop above):
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
I want the addVenue method to be able to take multiple arguments and update the VenueList class. Yet, when I call the addVenue method in the for loop, I can only pass it String result (from the parameters of the loop) and can't figure out how to pass it a second argument (which should also come from the JSON parsed by getResultsFromJson) so I've used "HELLO WORLD" as a placeholder for now.
I realize getResultsFromJson only has one list returned. I need to be able to take multiple elements from the JSON object that I parse, and then add them to VenueList in the right order.
So my questions are:
1) Given the getResultsFromJson method and the for loop, how can I use the addVenue() method as designed? How do I parse multiple elements from the JSON, and then add them to the VenueList at the same time? I plan on adding more arguments to it later on, but I assume if I can make it work with two, I can make it work with four or five.
2) If that's not possible, how should the getResultsFromJson, the for loop, and the addVenue method be redesigned to work properly together?
Please let me know if you need more detail or code - happy to provide. Thank you!
EDIT - Full VenueList class:
public class VenueList {
private static ArrayList<String> venueNames;
private static ArrayList<String> venueGeos;
public VenueList() {
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
}
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
public static String getVenueName(int position) {
return venueNames.get(position);
}
public static String getVenueGeo(int position) {
return venueGeos.get(position);
}
public static void clearList() {
venueNames.clear();
venueGeos.clear();
}
}
Clarification: I will have additional ArrayLists for each element of data that I want to store about a venue (phone number, address, etc etc)
1) I don't think methods getResultsFromJson(String json) and addVenue(String name, String geo) fit your needs.
2) I would consider rewriting method getResultsFromJson(String json) to something like this:
private static SortedMap<Integer, List<String>> getResultsFromJson(String json) {
Map<Integer, String> resultMap = new TreeMap<Integer, String>();
//...
return resultMap;
}
where the number of keys of your map should be equal to the number of objects you're extracting info, and each one of them will properly have their own list of items just in the right order you extract them.
With this approach you can certainly change your logic to something like this:
// grab your retuned map and get an entrySet, the just iterate trough it
SortedMap<Integer, String> result = returnedMap.entrySet();
for (Entry<Integer, String> result : entrySet) {
Integer key = result.getKey(); // use it if you need it
List<String> yourDesiredItems = result.getValue(); // explicitly shown to know how to get it
VenueList.addVenue(yourDesiredItems);
}
public static void addVenue(List<String> yourDesiredItems) {
// refactor here to iterate the items trough the list and save properly
//....
}
EDIT -- as you wish to avoid the go-between map i'm assuming you need nothing to return from the method
First i'm providing you with a solution to your requirements, then i'll provide you with some tips cause i see some things that could smplify your design.
To save VenueList things directly from getResultsFromJSON do something like this:
private static void getResultsFromJson(String json) {
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
//FOR EXAMPLE HERE IS WHERE YOU NEED TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then...
VenueList.addVenue(name, geo, ..., etc);
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
}
This implies that your addVenue method should know receive all params needed; as you can see this is just a way (that you can consider a workaround to your needs), however as i don't know all requirements that lead you to code this model, i will point to a few things you might consider:
1. If there's a reason for VenueList class to use everything static, consider doing this:
static{
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
//....
}
private VenueList(){
}
This way you won't need to get an instance every time and also will avoid null pointer exceptions when doing VenueList.addVenue(...) without previous instantiation.
2. Instead of having an ArrayList for every characteristic in VenueList class consider defining a model object for a Venue like this:
public class Venue{
String name;
String geo;
//... etc
public Venue(){
}
// ... getters & setters
}
then if you need that VenueList class you will just have a list o Venue objects (List<Venue>), this means that instead of calling the method addVenue, you will first create a brand new instance of Venue class and will call the setter method of each characteristic, as an example of the refactored for loop from the workaround i provided you you'd be using something like this:
List<Venue> myListOfVenues = new ArrayList<Venue>();
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
// THIS WOULD REMAIN THE SAME TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then instead of calling VenueList.addVenue(name, geo, ..., etc)...
Venue v = new Venue();
v.setName(name);
v.setGeo(geo);
// ...etc
myListOfVenues.add(v);
}
// Once you're done, set that List to VenueList class
VenueList.setVenueList(myListOfVenues);
So VenueList class would now have a single property List<Venue> venueList; and would suffer minor tweeks on methods getVenueName, etc... and everything would be more readable... i hope this helps you to get another approach to solve your problem, if i still don't make my point let me know and i'll try to help you out...