Firebase and AngularFire - $add in a array - unexpected behaviour - firebase

dayPath = ref.path.toString() + '/' + configId + '/screens/' + screenIndex + '/days/',
// the ref for the days object
daysRef = fbutil.ref(dayPath),
// the sync for the days object
daysSync = fbutil.syncObjectReference(daysRef);
// the collection as a $firebase array
var list = daysSync.$asArray(),
items = [],
number;
console.log(list);
list.$add({dummy: 'Test'});
According with the documentation, when I use $add with $asArray, the $add supposed to do a "push". But instead it's creating a hash key instead a numeric index.
So, the dummy: test has a parent containing a hash key. The expected is a numeric index, I mean : array item.
Can someone give me some help? I just have 1 week of experience in this database.
The result is this one...
screens
...0
.......days
..........0
..........1
..........2
.........-JrT5ZATDELIR3gXAvah
................dummy: test

AngulareFire is built on the Firebase JavaScript SDK. So when AngularFire's documentation says it uses push internally, it is not referring to JavaScript's Array.push, but to Firebase's push operation. And Firebase's push generates its own keys, it does not generate regular array indexes.
The reason for that is best explained in Firebase's documentation on arrays, but essentially boils down to: arrays don't work well in distributed environments, because all clients have to agree on the array.length in order to be able to add a new item.
So $firebaseArray.$add will generated a so-called push ID. They are ordered, like array indexes, but can be generated across clients without risk of conflicts.
I noticed that you're on a somewhat older version of AngularFire. I highly recommend that you follow the "official" quickstart and guide for AngularFire.

I would like to comment but i don't have enough reputation yet so i'm doing it here.
The solution in my eyes is very simple:
Instead of:
list.$add({dummy: 'Test'});
Do:
list[index] = {dummy: 'Test'};

Related

How to do pattern searching in fire base real time DB [duplicate]

I am using firebase for data storage. The data structure is like this:
products:{
product1:{
name:"chocolate",
}
product2:{
name:"chochocho",
}
}
I want to perform an auto complete operation for this data, and normally i write the query like this:
"select name from PRODUCTS where productname LIKE '%" + keyword + "%'";
So, for my situation, for example, if user types "cho", i need to bring both "chocolate" and "chochocho" as result. I thought about bringing all data under "products" block, and then do the query at the client, but this may need a lot of memory for a big database. So, how can i perform sql LIKE operation?
Thanks
Update: With the release of Cloud Functions for Firebase, there's another elegant way to do this as well by linking Firebase to Algolia via Functions. The tradeoff here is that the Functions/Algolia is pretty much zero maintenance, but probably at increased cost over roll-your-own in Node.
There are no content searches in Firebase at present. Many of the more common search scenarios, such as searching by attribute will be baked into Firebase as the API continues to expand.
In the meantime, it's certainly possible to grow your own. However, searching is a vast topic (think creating a real-time data store vast), greatly underestimated, and a critical feature of your application--not one you want to ad hoc or even depend on someone like Firebase to provide on your behalf. So it's typically simpler to employ a scalable third party tool to handle indexing, searching, tag/pattern matching, fuzzy logic, weighted rankings, et al.
The Firebase blog features a blog post on indexing with ElasticSearch which outlines a straightforward approach to integrating a quick, but extremely powerful, search engine into your Firebase backend.
Essentially, it's done in two steps. Monitor the data and index it:
var Firebase = require('firebase');
var ElasticClient = require('elasticsearchclient')
// initialize our ElasticSearch API
var client = new ElasticClient({ host: 'localhost', port: 9200 });
// listen for changes to Firebase data
var fb = new Firebase('<INSTANCE>.firebaseio.com/widgets');
fb.on('child_added', createOrUpdateIndex);
fb.on('child_changed', createOrUpdateIndex);
fb.on('child_removed', removeIndex);
function createOrUpdateIndex(snap) {
client.index(this.index, this.type, snap.val(), snap.name())
.on('data', function(data) { console.log('indexed ', snap.name()); })
.on('error', function(err) { /* handle errors */ });
}
function removeIndex(snap) {
client.deleteDocument(this.index, this.type, snap.name(), function(error, data) {
if( error ) console.error('failed to delete', snap.name(), error);
else console.log('deleted', snap.name());
});
}
Query the index when you want to do a search:
<script src="elastic.min.js"></script>
<script src="elastic-jquery-client.min.js"></script>
<script>
ejs.client = ejs.jQueryClient('http://localhost:9200');
client.search({
index: 'firebase',
type: 'widget',
body: ejs.Request().query(ejs.MatchQuery('title', 'foo'))
}, function (error, response) {
// handle response
});
</script>
There's an example, and a third party lib to simplify integration, here.
I believe you can do :
admin
.database()
.ref('/vals')
.orderByChild('name')
.startAt('cho')
.endAt("cho\uf8ff")
.once('value')
.then(c => res.send(c.val()));
this will find vals whose name are starting with cho.
source
The elastic search solution basically binds to add set del and offers a get by wich you can accomplish text searches.
It then saves the contents in mongodb.
While I love and reccomand elastic search for the maturity of the project, the same can be done without another server, using only the firebase database.
That's what I mean:
(https://github.com/metaschema/oxyzen)
for the indexing part basically the function:
JSON stringifies a document.
removes all the property names and JSON to leave only the data
(regex).
removes all xml tags (therefore also html) and attributes (remember
old guidance, "data should not be in xml attributes") to leave only
the pure text if xml or html was present.
removes all special chars and substitute with space (regex)
substitutes all instances of multiple spaces with one space (regex)
splits to spaces and cycles:
for each word adds refs to the document in some index structure in
your db tha basically contains childs named with words with childs
named with an escaped version of "ref/inthedatabase/dockey"
then inserts the document as a normal firebase application would do
in the oxyzen implementation, subsequent updates of the document ACTUALLY reads the index and updates it, removing the words that don't match anymore, and adding the new ones.
subsequent searches of words can directly find documents in the words child. multiple words searches are implemented using hits
SQL"LIKE" operation on firebase is possible
let node = await db.ref('yourPath').orderByChild('yourKey').startAt('!').endAt('SUBSTRING\uf8ff').once('value');
This query work for me, it look like the below statement in MySQL
select * from StoreAds where University Like %ps%;
query = database.getReference().child("StoreAds").orderByChild("University").startAt("ps").endAt("\uf8ff");

Firebase and Angularfire nightmare migration for Update

I am new to firebase and I am having a bit of a nightmare trying to adapt old code to what is now deprecated and what is not. I am trying to write a function which updates one "single" record in my datasource using the now approved $save()promise but it is doing some really strange stuff to my data source.
My function (should) enables you to modify a single record then update the posts json array. However, instead of doing this, it deletes the whole datasource on the firebase server and it is lucky that I am only working with testdata at this point because everything would be gone.
$scope.update = function() {
var fb = new Firebase("https://mysource.firebaseio.com/Articles/" + $scope.postToUpdate.$id);
var article = $firebaseObject(ref);
article.$save({
Title: $scope.postToUpdate.Title,
Body: $scope.postToUpdate.Body
}).then(function(ref) {
$('#editModal').modal('hide');
console.log($scope.postToUpdate);
}, function(error) {
console.log("Error:", error);
});
}
Funnily enough I then get a warning in the console "after" I click the button:
Storing data using array indices in Firebase can result in unexpected behavior. See https://www.firebase.com/docs/web/guide/understanding-data.html#section-arrays-in-firebase for more information. Also note that you probably wanted $firebaseArray and not $firebaseObject.
(No shit?) I am assuming here that $save() is not the right call, so what is the equivalent of $routeParams/$firebase $update()to do a simple binding of the modified data and my source? I have been spending hours on this and really don't know what is the right solution.
Unless there's additional code that you've left out, your article $firebaseObject should most likely use the fb variable you created just before it.
var article = $firebaseObject(fb);
Additionally, the way in which you're using $save() is incorrect. You need to modify the properties on the $firebaseObject directly and then call $save() with no arguments. See the docs for more.
article.Title = $scope.postToUpdate.Title;
article.Body = $scope.postToUpdate.Body;
article.$save().then(...

Firebase REST API Query Parameters?

Is it possible to filter data returned by the Firebase REST API using query parameters? I don't see it mentioned one way or an other in the docs, but the client libraries support it, so I'm hoping it's possible. Thanks.
It might be a bit late to answer, but Firebase does allow querying data via REST.
You can use the orderby option together with limitToLast, startAt etc just like you would when using the SDK.
Checkout the Firebase guide for more details
I fought a little bit to have it working.
I actually needed 2 things:
combine limitToLast with orderBy as mentioned by idan
URL getUrl = new URL( url + "news.json?orderBy=\"timestamp\"&limitToLast=5" );
add a rule in the database to declare an index on this "column"
"news" : { ".indexOn": "timestamp" }
Firebase provides querying parameters. However, I don't think they are the querying parameters you are expecting them to be, which are ones that filter data. Firebase REST API provides querying options like auth, print, callback, format, and download. Check docs here
Without ordering by certain field, By combining params orderBy="$key" and limitToLast=5 you can get the last 5 of inserted data ordered by it's key
The documentation can be looked at here

Firebase "Where" like search

Tryng to get a simple result using "Where" style in firebase but get null althe time, anyone can help with that?
http://jsfiddle.net/vQEmt/68/
new Firebase("https://examples-sql-queries.firebaseio.com/messages")
.startAt('Inigo Montoya')
.endAt('Inigo Montoya')
.once('value', show);
function show(snap) {
$('pre').text(JSON.stringify(snap.val(), null, 2));
}
Looking at the applicable records, I see that the .priority is set to the timestamp, not the username.
Thus, you can't startAt/endAt the user's name as you've attempted here. Those are only applicable to the .priority field. These capabilities will be expanding significantly over the next year, as enhancements to the Firebase API continue to roll out.
For now, your best option for arbitrary search of fields is use a search engine. It's wicked-easy to spin one up and have the full power of a search engine at your fingertips, rather than mucking with glacial SQL-esque queries. It looks like you've already stumbled on the appropriate blog posts for that topic.
You can, of course, use an index which lists users by name and stores the keys of all their post ids. And, considering this is a very small data set--less than 100k--could even just grab the whole thing and search it on the client (larger data sets could use endAt/startAt/limit to grab a recent subset of messages):
new Firebase("https://examples-sql-queries.firebaseio.com/messages").once('value', function(snapshot) {
var messages = [];
snapshot.forEach(function(ss) {
if( ss.val().name === "Inigo Montoya" ) {
messages.push(ss.val());
}
});
console.log(messages);
});
Also see: Database-style queries with Firebase

Dynamics GP Web Service -- Returning list of sales order based on specific criteria

For a web application, I need to get a list or collection of all SalesOrders that meet the folowing criteria:
Have a WarehouseKey.ID equal to "test", "lucmo" or "Inno"
Have Lines that have a QuantityToBackorder greater than 0
Have Lines that have a RequestedShipDate greater than current day.
I've succesfully used these two methods to retrieve documents, but I can't figure out how return only the ones that meet above criteria.
http://msdn.microsoft.com/en-us/library/cc508527.aspx
http://msdn.microsoft.com/en-us/library/cc508537.aspx
Please help!
Short answer: your query isn't possible through the GP Web Services. Even your warehouse key isn't an accepted criteria for GetSalesOrderList. To do what you want, you'll need to drop to eConnect or direct table access. eConnect has come a long way in .Net if you use the Microsoft.Dynamics.GP.eConnect and Microsoft.Dynamics.GP.eConnect.Serialization libraries (which I highly recommend). Even in eConnect, you're stuck with querying based on the document header rather than line item values, though, so direct table access may be the only way you're going to make it work.
In eConnect, the key piece you'll need is generating a valid RQeConnectOutType. Note the "ForList = 1" part. That's important. Since I've done something similar, here's what it might start out as (you'd need to experiment with the capabilities of the WhereClause, I've never done more than a straightforward equal):
private RQeConnectOutType getRequest(string warehouseId)
{
eConnectOut outDoc = new eConnectOut()
{
DOCTYPE = "Sales_Transaction",
OUTPUTTYPE = 1,
FORLIST = 1,
INDEX1FROM = "A001",
INDEX1TO = "Z001",
WhereClause = string.Format("WarehouseId = '{0}'", warehouseId)
};
RQeConnectOutType outType = new RQeConnectOutType()
{
eConnectOut = outDoc
};
return outType;
}
If you have to drop to direct table access, I recommend going through one of the built-in views. In this case, it looks like ReqSOLineView has the fields you need (LOCNCODE for the warehouseIds, QTYBAOR for backordered quantity, and ReqShipDate for requested ship date). Pull the SOPNUMBE and use them in a call to GetSalesOrderByKey.
And yes, hybrid solutions kinda suck rocks, but I've found you really have to adapt if you're going to use GP Web Services for anything with any complexity to it. Personally, I isolate my libraries by access type and then use libraries specific to whatever process I'm using to coordinate them. So I have Integration.GPWebServices, Integration.eConnect, and Integration.Data libraries that I use practically everywhere and then my individual process libraries coordinate on top of those.

Resources