This question already has an answer here:
Firebase sort by points depending on date
(1 answer)
Closed 4 years ago.
I have a database that looks like this:
{
firstitem : {
"name" : "first_item_name",
"date" : "29/11/2018",
"user" : "random user",
"url" : "My Url",
"tag" : "firstitem"
},
seconditem : {
"name" : "second_item_name",
"date" : "20/11/2018"
"user" : "another user",
"url" : "a url",
"tag" : "seconditem"
},
thirditem : {
"name" : "third_item_name",
"date" : "20/11/2017"
"user" : "another user",
"url" : "a url",
"tag" : "thirditem"
}
ect....
}
I want to be able to have an option to sort by date, starting at the newest, and descending to the oldest. How can I achieve this?
This is my method for calling the firebase strings at the moment:
if (dataSnapshot.exists()) {
Log.i("Event", "Added");
Firebase_Strings dlStrings = dataSnapshot.getValue(Firebase_Strings.class);
p9p_strings.DOCUMENTARY_NAME.add(dlStrings.name);
p9p_strings.DOCUMENTARY_SYNOPSIS.add(dlStrings.about);
p9p_strings.DOCUMENTARY_URL.add(dlStrings.url);
p9p_strings.DOCUMENTARY_UPLOADED.add(dlStrings.date);
p9p_strings.DOCUMENTARY_TAG.add(dlStrings.tag);
There is no way in which you can sort your items by date if you are storing the date as String "29/11/2018" and not as a timestamp.
To solve this, you should change the type of your date property to number.
And here you can how to add and get back the timestamp.
Related
I have a content node that I retrieve from a Firebase Realtime Database.
I utilize .orderByChild("time") to get a Data Snapshot of the first 5 blog objects ordered by their earliest timestamps. I
am currently attempting to utilize .indexOn : "time" instead so that I do not have to utilize .orderByChild("time") as I am expecting for the blog objects to already be ordered by their timestamp by back-end when they are retrieved. (I am going to be working with a very large number of blog objects, so I want to utilize .indexOn : "time" in back-end instead of orderByChild("time") in front-end to increase efficiency). Currently, .indexOn does not work and the data isn't ordered by their time fields when it is retrieved.
query without .indexOn
// this works fine
// startAt is utilized for saving last blog object retrieved to retrieve more data
query =
FirebaseDatabase.getInstance().getReference()
.child("content")
.orderByChild("time")
.startAt(nodeId)
.limitToFirst(5);
query with .indexOn
// this along with the Firebase rules below does not return the same result as above
// startAt is utilized for saving last blog object retrieved to retrieve more data
query =
FirebaseDatabase.getInstance().getReference()
.child("content")
.startAt(nodeId)
.limitToFirst(5);
Firebase rules:
{
"rules": {
".read": true,
".write": true,
"content" : {
".indexOn": "time"
}
}
}
JSON structure of data in Firebase :
"content" : {
"blog-0001" : {
"content_id" : "blog-0001",
"image" : "someimage",
"time" : 13,
"title" : "title1",
"type" : "blog"
},
"blog-0002" : {
"content_id" : "blog-0002",
"image" : "someimage",
"time" : 12,
"title" : "title2",
"type" : "blog"
},
"blog-0003" : {
"content_id" : "blog-0003",
"image" : "someimage",
"time" : 11,
"title" : "title3",
"type" : "blog"
},
"blog-0004" : {
"content_id" : "blog-0004",
"image" : "someimage",
"time" : 15,
"title" : "title4",
"type" : "blog"
}
...
}
You seem to be misunderstanding what .indexOn does, and how it related to orderByChild("time").
To retrieve child nodes from content ordered by (and possibly also filtered on) time, you will always need to call orderByChild("time").
If you define an index (using ".indexOn": "time") that ordering and filtering will be done on the server.
Without an index, all data under content will be downloaded to the client, and the ordering/filtering will be performed client side.
So .indexOn is not a replacement for orderByChild. Instead the two work hand in hand to perform efficient ordering and filtering of data.
"locs" : {
"-Lci8jGrXCEP-r6LBxD8" : {
"title" : "Marriage"
},
"-Lci9UNW80J2Jap_UHwj" : {
"title" : "Visit"
}
},
My firebase realtime database looks like this. I want to add three other values under this same push key namely latitude and longitude and address.
mDatabase.child("users").child(mUserId).child("locs").push().child("title").setValue(text.getText().toString());
This works in first activity. In second activity I retrieve lat and long and save it in a string lat and long respectively. Now I want these two values and addr to be saved under this same key.
This is my expected result
"locs" : {
"-Lci8jGrXCEP-r6LBxD8" : {
"title" : "Marriage"
"lat" : "xxx.xxxxxx"
"long" : "xxx.xxxxxx"
"addr" : "Street 112 xxxx"
},
"-Lci9UNW80J2Jap_UHwj" : {
"title" : "Visit"
"lat" : "xxx.xxxxxx"
"long" : "xxx.xxxxxx"
"addr" : "Street 1212 Flat 6"
}
},
You'll need to do two things:
Make sure the second activity knows the key to update. You can do this either by passing the key along from the first activity to the next (in an intent or in shared preferences), or by looking it up in the second activity based on some other unique property that you know the value of.
Update the location for that key, instead of generating a new one. You do this by calling update() instead of set() and using child(key) instead of push(). So:
Map<String, Object> values = new HashMap<String, Object>();
values.put("title", "new updated title");
values.put("newprop", "value of new prop");
mDatabase.child("users").child(mUserId).child("locs").child(key).updateChildren(values);
Alright, i've got a simple question. I have a simple Document in MongoDB which holds a sub-document called "penalties".
Now i want to find the Document (here with the _id "Cammeritz") by a String in the sub-document ("penalties"), e.g. "penaltyid = 0f77d885-6597-3f47-afb1-0cee2ea3ece1". Can you maybe help me? Best would be an explanation for Java but it is okay if you maybe just help with a normal MongoDB query.
{
"_id" : "Cammeritz",
"penalties" : [
{
"_id" : null,
"date" : ISODate("2017-09-25T20:01:23.582Z"),
"penaltyid" : "0f77d885-6597-3f47-afb1-0cee2ea3ece1",
"reason" : "Hacking",
"teammember" : "Luis",
"type" : "ban"
},
{
"_id" : null,
"date" : ISODate("2017-09-25T20:01:23.594Z"),
"penaltyid" : "7f5411b0-e66a-33b3-ac4f-4f3159aa88a9",
"reason" : "Spam",
"teammember" : "BluingFX",
"type" : "kick"
}
],
"isBanned" : true,
"isMuted" : false
}
Oops, I misread your question. You'll need to use dot notation. db.collection.find( { penalties.penaltyid: '0f77d885-6597-3f47-afb1-0cee2ea3ece1' } ) For more info see Query on a Nested Field.
Original answer:
db.collection.find( { penalties: "0f77d885-6597-3f47-afb1-0cee2ea3ece1" } ) should work. For more see Query an Array for an Element from the mongodb docs. I'm not very familiar with Java so I can't help much there.
Using Morphia, is it possible to perform a saveOrUpdate / upsert operation on an object embedded inside an array.
Consider the following document :
{
_id : "abcd",
myArray : [{
"key" : "areaTotal",
"value" : "101.9",
"label" : "Total area (municipality)"
}, {
"key" : "areaUrban",
"value" : "803",
"label" : "Total area (urban)"
}, {
"key" : "populationDensity",
"value" : "15991",
"label" : "Population desnsity"
}
]
}
Is there a clean way to replace for example array element with key "areaUrban" by another object
such as
{
"key" : "areaUrban",
"value" : "123",
"label" : "a new label"
}
For now I do it in two update operations first delete, then add :
UpdateOperations<T> ops = createUpdateOperations().removeAll("myArray ", new BasicDBObject("key", "areaUrban"));
update(createQuery().field("_id").equal(myObjId),ops);
UpdateOperations<T> ops2 = createUpdateOperations().add("myArray ", myReplacementObject);
update(createQuery().field("_id").equal(myObjId),ops2);
Which works fine but can I do it in only one update op (either with morphia or with plain mongo java driver) ?
Also if a matching object did not originally exist in the array, then the myReplacementObject object should just be added to the array.
thanks
With the $ positional operator:
db.test.update({_id: "abcd", "myArray.key": "areaUrban"}, {$set: {"myArray.$.value": 123, "myArray.$.label": "a new label"}})
[Edit] As JohnnyHK mentions in the comments this won't upsert the nested document if it doesn't exist.
I have a little bug with my script:
BasicDBObject change = new BasicDBObject();
BasicDBObject account =
new BasicDBObject().append("$set", new BasicDBObject().append("status", 0));
account.append("pos.X", getX());
account.append("pos.Y", getY());
account.append("pos.Z", getZ());
change.append("pseudo", gPlayer);
coll.update(change, account);
And the structure of mongoDB is :
{
pseudo: "pseudo"
email: "email"
password: "password"
status: "1"
pos: [
{X: "90.45}
{Y: "90.45}
{Z: "90.45}
]
}
But this is not working! No value is modified.
Thanks for your help.
Java is a very verbose language, and sometimes it is easiest to first write your query using the JS shell, make sure it performs as desired, and then translate it into Java.
By adding System.out.println(account.toString()) to your Java code, I can see that your Update document looks like the following, which is not valid:
{ "$set" : { "status" : 0} , "pos.X" : "90.45" , "pos.Y" : "90.45" , "pos.Z" : "90.45"}
From your question, it is not entirely clear what you would like your updated document to look like, but I am guessing that you would like to modify the values of "status" and "pos.0.X", "pos.1.Y", and "pos.2.Z". Because X, Y, and Z are all stored as individual embedded documents inside an array, they will have to be referenced by their positions in order to be updated at the same time. If possible, you might find it preferable to rearrange your document structure such that X, Y, and Z are all stored inside the same document, like so:
"pos" : {
"X" : "0",
"Y" : "0",
"Z" : "0"
}
This way, you will be able to access each variable more easily using dot notation, pos.X, pos.Y, pos.Z, which from your post looks like what you were intending. More information on embedded documents may be found in the "Dot Notation (Reaching into Objects)" documentation:
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
Here is an Update statement that will modify the above values:
> db.pseudo.find({ "pseudo" : "gPlayer"}).pretty()
{
"_id" : ObjectId("4f904ebb5bebd4375b759c90"),
"email" : "email",
"password" : "password",
"pos" : [
{
"X" : "90.45"
},
{
"Y" : "90.45"
},
{
"Z" : "90.45"
}
],
"pseudo" : "gPlayer",
"status" : "1"
}
> db.pseudo.update({"pseudo" : "gPlayer"}, { "$set" : { "status" : 0 , "pos.0.X" : "0" , "pos.1.Y" : "0" , "pos.2.Z" : "0"}})
> db.pseudo.find({ "pseudo" : "gPlayer"}).pretty()
{
"_id" : ObjectId("4f904ebb5bebd4375b759c90"),
"email" : "email",
"password" : "password",
"pos" : [
{
"X" : "0"
},
{
"Y" : "0"
},
{
"Z" : "0"
}
],
"pseudo" : "gPlayer",
"status" : 0
}
>
Translated into Java this is:
BasicDBObject change = new BasicDBObject("pseudo", "gPlayer");
BasicDBObject setDoc = new BasicDBObject();
setDoc.append("status", "0");
setDoc.append("pos.0.X", "0");
setDoc.append("pos.1.Y", "0");
setDoc.append("pos.2.Z", "0");
BasicDBObject account = new BasicDBObject("$set", setDoc);
coll.update(change, account);
I realize that I guessed a little bit about exactly the update that you would like to do, but hopefully the above will get you pointed in the right direction!