firebase order by datetime desc and asc - javascript

so i learn something new from firebase realtime for chat purpose..
but i still confuse how to make an action "how to order by like php"
so i have some code like this
var timenow=moment().format('YYYY-MM-DD HH:m:s');
firebase.database().ref('message/notification').orderByChild("lastupdate").startAt(timenow).on('value',function(snapshot){
listuser.innerHTML+=snapshot.val().name;
});
here my database
How to order limit asc and desc method with lastupdate child? im search for reference that mostly tutorial for android.

You're already retrieving the data ordered by their lastupdate and starting at "now". But your code for then handling the results is incorrect.
In the callback you'll want to loop over the results from the database with forEach and then add each individual node to the HTML. That'd look something like this:
firebase.database().ref('message/notification').orderByChild("lastupdate").startAt(timenow).on('value',function(snapshot){
listuser.innerHTML = "";
snapshot.forEach(function(notificationSnapshot) {
listuser.innerHTML += notificationSnapshot.val().name;
});
});
Alternatively, you can listen for the child_added event instead of value, which means that Firebase calls you for each individual child that is added. By listening to child_added and you won't need the loop in the callback:
firebase.database().ref('message/notification').orderByChild("lastupdate").startAt(timenow).on('child_added',function(snapshot){
listuser.innerHTML += snapshot.val().name;
});
There is no way to retrieve your data from Firebase in descending order, so you'll have to reverse it in your application code. The simplest way to do that, is by changing how you add it to the HTML to always prepend the new data to the existing HTML:
listuser.innerHTML = snapshot.val().name + listuser.innerHTML;
Finally: there are many thousands of questions about Firebase already, so it really helps if you can tailor your search to what you need. For example: to find questions about the Realtime Database in JavaScript, I tend to search for the combination of those tags. By adding more terms to the search, you can usually zoom in pretty well. For example: these are questions about querying in descending order.

Related

How to load data onScroll in ReactNative with Firebase Realtime Database

i want to load data from my realtime database, but only 15 entries everytime, because the database is huge. The database has a name of the vocable and got information about it like translations and stats. I want to sort it alphabetic by the value "wordENG", but there is a problem, when i use orderByChild like this:
database()
.ref(`vocables/${UID}`)
.orderByChild("wordENG")
.startAt(requestCount)
.limitToFirst(15)
.once("value")
.then(snap => {
console.log(snap.val());
})
When i try to use startAt, to get the data on scrolling, i get the problem that startAt need to be a string, so a word of the database list. I don't want to store this word everytime and search for new one after that, but currently i cannot see another way. Is there a way to get data alphabetic on scrolling with a number to count or do i need to realize it with saving the last word and search from there?
Pagination with Firebase queries work based on knowing the anchor item, not on offsets. So you will need to indeed know the wordENG value of the node to start at (or start after with the relatively new startAfter method), and possibly the key (if there may be multiple child nodes with the same wordENG value.
If you're new to Firebase, I recommend also reading some of the previous questions about pagination, as this comes up regularly.

Meteor MongoDB Filter Parent Records by Child Fields

How would I go about filtering a set of records based on their child records.
Let's say I have a collection Item that has a field to another collection Bag called bagId. I'd like to find all Items where a field on Bags matches some clause.
I.e. db.Items.find( { "where bag.type:'Paper' " }) . How would I go about doing this in MongoDB. I understand I'd have to join on Bags and then link where Item.bagId == Bag._id
I used Studio3T to convert a SQL GROUP BY to a Mongo aggregate. I'm just wondering if there's any defacto way to do this.
Should I perform a data migration to simply include Bag.type on every Item document (don't want to get into the habit of continuously making schema changes everytime I want to sort/filter Items by Bag fields).
Use something like https://github.com/meteorhacks/meteor-aggregate (No luck with that syntax yet)
Grapher https://github.com/cult-of-coders/grapher I played around with this briefly and while it's cool I'm not sure if it'll actually solve my problem. I can use it to add Bag.type to every Item returned, but I don't see how that could help me filter every item by Bag.type.
Is this just one of the tradeoffs of using a NoSQL dbms? What option above is recommended or are there any other ideas?
Thanks
You could use the $in functionality of MongoDB. It would look something like this:
const bagsIds = Bags.find({type: 'paper'}, {fields: {"_id": 1}}).map(function(bag) { return bag._id; });
const items = Items.find( { bagId: { $in: bagsIds } } ).fetch();
It would take some testing if the reactivity of this solution is still how you expect it to work and if this would still be suitable for larger collections instead of going for your first solution and performing the migration.

How to know how many items a Firestore query will return while implementing pagination

Firestore has this guide on how to paginate a query:
Firestore - Paginate data with query cursors
They show the following example:
Paginate a query
Paginate queries by combining query cursors with the limit() method. For example, use the last document in a batch as the start of a cursor for the next batch.
var first = db.collection("cities")
.orderBy("population")
.limit(25);
return first.get().then(function (documentSnapshots) {
// Get the last visible document
var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
console.log("last", lastVisible);
// Construct a new query starting at this document,
// get the next 25 cities.
var next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
});
QUESTION
I get the example, but how can I know how many items (in total, without the limit restriction) that query will return? I'll need that to calculate the number of pages and control the pagination component, won't I?
I can't simply display next and back buttons without knowing the limit.
How is it supposed to be done? Am I missing something?
You can't know the size of the result set in advance. You have to page through all the results to get the total size. This is similar to not being able to know the size of a collection without also recording that yourself somewhere else - it's just not scalable to provide this information, in the way that Cloud Firestore needs to scale.
this is not possible, the iterator cannot know how many documents it contains, as they are fetched via a gRPC stream.
But there is a workaround... but you have to make a few stuff:
1) write a counter in a firebase doc, which you increment or decrement everything you make a transaction
2) store the count in a field of your new entry, like position 10 or something.
Then you create an index on that field (position DESC).
This way you can do a skip+limit with a where("position", "<", N).orderBy("position", DESC)
It's complex but it does the trick

Breeze - Getting All Navigation Properties For Array of Entities

I'm trying to figure out with Breeze how to expand a specific navigation property for all items in an array of entities with a single request.
On this page of the Breeze documentation it shows the following way of achieving this:
var orderEntityType = selectedOrders[0].entityType;
var navProp = orderEntityType.getNavigationProperty("OrderDetails");
var navQuery = EntityQuery
.fromEntityNavigation(selectedOrders, navProp)
.expand("Product");
manager.executeQuery(navQuery).fail(handleFail);
However, when I tried this I get the error
The 'entity' parameter must be an entity
So I looked up in the documentation specifically for the EntityQuery.fromEntityNavigation method and it shows:
// 'employee' is a previously queried employee
var ordersNavProp = employee.entityType.getProperty("Orders");
var query = EntityQuery.fromEntityNavigation(employee, ordersNavProp);
The documentation indicates that it is for a specific entity, not multiple. Which is consistent with the error I'm getting.
Is it possible to get all the navigation properties in a single request, or is the preferred way to iterate over an array making a request for each entity?
Basically, I'm working on filtering a list of items. My goal is that when a user selects a filter it then expands the needed navigation property at that time instead of loading all the data up front.
Thanks for the help.
I think this might be a typo or some out of date information on the navigation properties documentation page. According to the API documentation for EntityQuery.fromEntityNavigation, the first parameter should be a single entity, not an array. Took a look at the breeze code, didn't see any evidence that an array of entities could be passed.
As a workaround, you could construct the query a bit differently. Continuing with the Order/OrderDetails scenario, you could do something like this:
var subsetOfOrders = ..., // array containing the subset of orders whose OrderDetails we need to load
predicates = subsetOfOrders.map(function(order) { return new breeze.Predicate('OrderId', '==', order.OrderId()); }),
predicate = breeze.Predicate.or(predicates),
query = new breeze.EntityQuery('Orders').expand('OrderDetails').where(predicate);
manager.executeQuery(query)...
If you're able to query the order details directly you don't even need expand. Breeze will wire up the freshly loaded OrderDetails to the respective orders entities that are already cached in the entity manager:
var subsetOfOrders = ..., // array containing the subset of orders whose OrderDetails we need to load
predicates = subsetOfOrders.map(function(order) { return new breeze.Predicate('OrderId', '==', order.OrderId()); }),
predicate = breeze.Predicate.or(predicates),
query = new breeze.EntityQuery('OrderDetails').where(predicate);
manager.executeQuery(query)...
This predicate based workaround may or may not be feasible depending on the number of orders you're dealing with. Could end up with a long query string. You could then consider using a dedicated controller action (ie "OrderDetailsByOrderId(int[] orderIds)" and use the withParameters EntityQuery method to load the order details using the new action.
The documentation was in error. I just corrected it.
#Jeremy Danyow offered a superb explanation and a solution. I probably would use his approach to solve a specific use case.
The documentation now discusses the problem and describes yet another approach that might be more appropriate if you were trying to write a general utility.
// create an array of filter criteria (`wherePredicate`) for each order
var predicates = orders.map(function (order) {
return EntityQuery.fromEntityNavigation(order,'OrderDetails')
.wherePredicate;
});
// OR the predicates together
var filter = breeze.Predicate.or(predicates);
EntityQuery.from('OrderDetails')
.where(filter)
.expand('Product')
.using(em).execute().catch(handleFail);
Thanks to you both for identifying the problem and working through it.

CouchDB map/reduce function to show limited results for a user by date

I am one of many SQL users who probably have a hard time transitioning to the NoSQL world, and I have a scenario, where I have tonnes of entries in my database, but I would only like to get the most recent ones, which is easy, but then it should all be for the same user. I'm sure it's simple, but after loads of trial and error without a good solution, I'm asking you for help!
So, my keys look like this.. (because I'm thinking that's the way to go!)
emit([doc.eventTime, doc.userId], doc);
My question then is, how would I go about only getting the 10 last results from CouchDB? For that one specific user. The reason why I include the time as key, is because I think that's the simplest way to sort the results descending, as I want the ten last actions, for example.
If I had to do it in SQL i'd do this, to give you an exact example.
SELECT * FROM table WHERE userId = ID ORDER BY eventTime DESC LIMIT 10
I hope someone out there can help :-)
Change your key to:
emit([doc.userId, doc.eventTime], null);
Query with:
view?descending=true&startkey=[<user id>,{}]&endkey=[<user id>]&limit=10
So add something like this to a view...
"test": {
"map": "function(doc) { key = doc.userId; value = {'time': doc.eventTime, 'userid': doc.userId}; emit(key, value)}"
}
And then call the view...(assuming userId = "123"
http://192.168.xxx.xxx:5984/dbname/_design/docname/_view/test?key="123"&limit=10
You will need to add some logic to the map to get the most recent, as I don't believe order is preserved in any manner.

Categories

Resources