I'm trying desperately to setup Firebase database sharding into an Ionic v3 (Angular 4) app in order to decrease the Realtime Database load values.
I almost made it work, except one small detail.
So what I've done is the following:
initialized a new app
const app2 = firebase.initializeApp({ databaseURL: "https://app2.firebaseio.com/" }, "app2");
then in a service I'm using AngularFireDatabase:
constructor(private afDatabase: AngularFireDatabase) {}
then when I want to simply get a list of items from the second database I do
this.afDatabase.list(firebase.database(app2).ref('/items'));
which works just fine.
But the problem now is that when I pass in a query object, like this
this.afDatabase.list(firebase.database(app2).ref('/items'), {
query: {
orderByChild: "item_id",
equalTo: 5
}
});
this query is completely ignored, it actually returns the whole list under /items.
The problem is caused by a bug is in list() and object() methods implementation in database.ts file under angularfire2 package, version 2.0.0-beta.8
More exactly, this line
isRef: () => FirebaseObjectFactory(urlOrRef)
should actually be
isRef: () => FirebaseObjectFactory(urlOrRef, opts)
both under list() and object() functions.
With this fix, and a rebuild of angularfire2 package, I managed to made it work.
Related
I'm using strapi alongside knex, however strapi doesn't create any migrations and when you edit a content type (Model) by deleting a property or renaming it, it doesn't delete the targeted property, it just creates a new one, and when you delete a model it doesn't actually delete the table on the database.
This is really annoying because you'll end up with a lot of redundancies and unused tables and fields while developing.
What I'm doing is overriding the Strapi controllers that are responsible for creating, removing or updating a model and I want to be able to create a migration with the new schema on those controllers and then run it so I keep my database clean and up-to-date with strapi's models.
I know about the existence of knex.migrate.make however it doesn't seem to address my issue and the docs don't really tell you how to provide the migration fields to that function.
I was able to also find this http://knexjs.org/#custom-migration-sources however once again the docs are not very clear on what options I can provide and how to solve my issue.
Ideally I would want to end up with something like:
updateModel({attributes, table}){
const updatedSchena = attributes
knex.migrate.make(`update_${table.name}_table`, updatedSchema);
}
Edit:
I was able to create the new migration at run time but the contents of the file remain empty.
This is what I have so far
New custom-migration-sources as indicated in the docs:
class MyMigrationSource {
// Must return a Promise containing a list of migrations.
// Migrations can be whatever you want, they will be passed as
// arguments to getMigrationName and getMigration
constructor(name, attributes) {
this.name = name
this.attributes = attributes
console.log('attributes: ', attributes)
}
getMigrations() {
// In this example we are just returning migration names
return Promise.resolve(['migration1'])
}
getMigrationName(migration) {
return migration;
}
getMigration() {
return {
up(knex) {
//const migrate = require('widget-knex-schema')
return migrate.createTable(knex, this.name, this.attributes)
},
down(knex) {
return knex.schema.dropTableIfExists(this.name)
}
}
}
}
Instantiate the new migration source
const migration = new MyMigrationSource(modelJSON.collectionName, formatedAttributes)
Create the new migration with the custom configuration:
knex.migrate.make(`update_${name}_table`, {
migrationSource: migration
})
And the result is a new migration with these contents:
exports.up = function(knex) {
};
exports.down = function(knex) {
};
NOTE: I know that ´widget-knex-schema´is working because I use for other manually created migrations.
Can anyone link to any working examples or solutions on how to create migrations in run time?
I'm using a library developed by Chris Esplin (firebase-paginator) but i get FirebasePaginator is not a constructor when i try to use it. I'm actually developing a PWA in Vue.js 2.0, the script where this is getting called it's in app-name/src/store/index.js which is the main file for manage vuex states, mutations, actions and getters.
var FirebasePaginator = require('firebase-paginator')
var options = {
pageSize: 20,
finite: true,
auth: 'SomeAuthToken',
retainLastPage: false
}
var ref = firebase.database().ref('track')
var paginator = new FirebasePaginator(ref, options)
var collection = null
paginator.once('value')
.then(() => {
collection = paginator.collection
console.log(paginator, collection)
})
I've tried with a custom paginator that found googling, i adapted to eslint rules and i get the same constructor error when i make the call with new
I'm unfamiliar with Vue.js, but I only ever designed FirebasePaginator to work with script tags for the browser or require calls for Node.js. The "not a constructor" error indicates that the library wasn't imported correctly.
Try adding /node_modules/firebase-paginator/firebase-paginator.js to the page in a script tag. I'm sure there's a way to get require('firebase-paginator') to work with require statements in the browser, but I don't use them that way myself, so if you figure it out, I'd welcome a pull request.
Also, make sure that you don't use your legacy admin auth token in the browser. I think the REST API will work with auth tokens from your authenticated user, but I haven't played with that feature in a while, so I'm uncertain. Infinite pagination may be easier to implement.
Does app.js get processed only once?. In that case, does it make sense to run setup queries in app.js so that I don't have to run it on every request?.
I have a table to countries and regions that I need in several requests.
I am looking at an implementation something like this https://stackoverflow.com/a/21133217/406659
No putting this in app.js does not make sense. I would create a models folder and encapsulate all of your database logic in a module within that folder. Then on startup of the app (ie on app.listen() callback) I would call a method from that module which does the setup for me. For example:
Some DB module in models
module.exports = {
setup: () => {
// Set up logic here - checking if tables exist etc
}
}
Then in app.js or equal
require <SOME DB MODULE>
app.listen(<PORT>, () => {
<SOME DB MODULE>.setup();
})
Note this is a generalised approach as I don't know the specifics of your setup - This approach just ensures encapsulated and reusable code. I've also used ES6 syntax where possible.
Hope this helps
Dylan
In sails.js, can a service use data or functions generated by a hook or by sails.config.bootstrap?
Or it's only the other way around?
EDIT: I was trying to add a hook to set up my rate limiter's parameters before sails lift, and then use this rate limiter from within the application.
The bootstrap file in config/bootstrap.js is intended mainly for setting up data, jobs, etc. that are specific to your app and may need to run only once. It's run after all of your models, services and hooks have already loaded, so it can rely on them.
You can use a hook method inside of a service method--you just can't use it to set up a service. So, this is okay:
// config/services/GoodService.js
module.exports = {
someMethod: function() {
var rateLimit = sails.hooks.someHook.getRateLimit();
}
};
This is not okay:
// config/services/BadService.js
var rateLimit = sails.hooks.someHook.getRateLimit();
module.exports = {
someMethod: function() {...do something with rateLimit...}
}
I've been migrating my app from RethinkDb to Firebase and have run into a wall trying to get my collections to save when calling collection.create(). The odd thing is, I have two instances of Backbone.Firebase.Collection in my app and one of them is able to create new objects properly. The other collection, which is seemingly identical, cannot write data and generates no error messages.
I have two Collections, each with their own type of Model:
1) Projects (Collection) -> Project (Model)
2) Projects (Collection) -> Shots (Collection) -> Shot (Model)
Here are the definitions for the above collections/models:
/* Projects Collection - An ordered list of Projects */
var ProjectModelFirebase = require('../models/projectModelFirebase.js');
module.exports = Backbone.Firebase.Collection.extend({
model: ProjectModelFirebase,
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Project Model - data layer for a single Project */
module.exports = Backbone.Firebase.Model.extend({
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Shots Collection - An ordered list of Shots */
var ShotModelFirebase = require('../models/shotModelFirebase.js');
module.exports = Backbone.Collection.extend({
model: ShotModelFirebase,
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Shot Model - data layer for a single Shot */
module.exports = Backbone.Firebase.Model.extend({
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
In my Projects route (routes file), I bind the collection to the view normally and call this.collection.create with some inputs from the template. I'm able to successfully create projects in this way and they show up in my Forge with no problem. I call the view from my route function:
// Display list of latest projects
projectsCollectionFirebase = new ProjectsCollectionFirebase();
var projectsView = new ProjectsView({collection: projectsCollectionFirebase});
In my Project route (routes file), I bind the project collection to the view and retrieve the project's information from Firebase normally:
// Display a single project
projectModelFirebase = new ProjectModelFirebase({id: project});
var projectView = new ProjectView({model: projectModelFirebase});
I then proceed (projectView file) to create a new collection of shots:
shotsCollectionFirebase = new ShotsCollectionFirebase();
shotsView = new ShotsView({ collection: shotsCollectionFirebase, project: this.model.get('id') });
The Shots view (ShotsView file) renders the template and input fields for the user to input a shot.
From here, I call this.collection.create when a user clicks the 'Save' button. Backbone recognizes the new model and updates the view accordingly, but Firebase doesn't act on it. There is an error message in the console that states 'Save called on a Firebase model, ignoring.' but I do not have any saves called out explicitly in my code.
I've tried turning on debugging and noticed that the 'projects' create command causes this message:
r:0: update {"path":"/projects/test","value":{"shots":null}}
Whereas the 'shots' collection does not ever trigger an 'update' event.
The files are nearly identical. The only thing difference I can spot is that the first example has only one collection loaded at a time whereas the second example loads a collection, grabs the data, then loads another collection as a result.
Any help would be appreciated.
You can find the full code for the project in my repo here: https://github.com/bdickason/shots/tree/firebase
There are two modes of operation in Backfire, one with models/collection that have the word 'Firebase' in them, eg: Backbone.Firebase.Model/Backbone.Firebase.Collection; and the other mode that uses regular backbone collections and models but have the 'firebase' property defined on them that overrides the backbone sync() method.
These two modes should not be mixed and matched. For example, if you're using a Backbone.Firebase.Collection, all the models in that collection will automatically be synchronized with the server any time a change is made to any model (same for Backbone.Firebase.Model). Calling save, or sync doesn't do anything because the changes are saved and synced in realtime as they happen.
Sometimes this isn't what you want in the app, for example, you want the user to explicitely click a save button before saving anything to Firebase. In these cases, it's best to use a regular Backbone collection or model, and simply provide the firebase property on them. You then need to call sync or save explicitely to put any changes on the local model/collection into Firebase.