- A deleted_at field is required on remote and meteor side.
- A external_id field is required on remote and meteor side.
- Remote must provide a RESTful api.
First call
DBSync.configure({
remote_root: Meteor.settings.remote_sync_root,
max_retries: 10,
poll_length: 'every 1 days', // Later.js text
restivus_options: { // Passed throuw to restivus
use_default_auth: false
}
});
var articleOut = {
"_id": {mapTo: "external_id"}, // Default
"title": {mapTo: "title"},
"author": {mapTo: "author"},
"externalId": {mapTo: "id"}, // Default
"deleted_at": {mapTo: "deleted_at"}, // Default
};
var articleIn = {
"id": {mapTo: "externalId"}, // Default
"title": {mapTo: "title"},
"author": {mapTo: "author"},
"deleted_at": {mapTo: "deleted_at"}, // Default
"updated_at": {mapTo: "updated_at"}, // Default
};
DBSync.addCollection({
collection: Articles,
remote_external_id_field: "id",
index: {
route: "/articles.json"
},
newDoc: {
route: "/articles.json",
field: "article"
},
updateDoc: { // For the moment we assume the route simply has the external Id as a suffix
route: "/articles/:id.json",
field: "article"
},
mapOut: articleOut,
mapIn: articleIn
});
var commentOut = {
"article_id": {mapTo: "articleId", mapFunc: function( val ){
// Always treat external ID's as string
if( val ){ return Articles.findOne({externalId: val.toString()})._id;}
}},
"title": {mapTo: "title"},
"body": {mapTo: "body"},
"author": {mapTo: "author"},
};
var commentIn = {
"article_id": {mapTo: "articleId", mapFunc: function( val ){ // Assume externalID is a string
if( val ){return Articles.findOne({externalId: val.toString()})._id;} }
},
"title": {mapTo: "title"},
"body": {mapTo: "body"},
"author": {mapTo: "author"},
};
DBSync.addCollection({
collection: Comments,
remote_external_id_field: "id",
index: {
route: "/comments.json"
},
newDoc: {
route: "/comments.json",
field: "comment"
},
updateDoc: {
route: "/comments/:id.json",
field: "comment"
},
mapOut: commentOut,
mapIn: commentIn
});
This must be called to start syncing. It must be called after all config is complete.
DBSync.start();
We also setup endpoints to restfully and in realtime update our local collections when the remote system changes. It uses 'nimble:restivus' under the hood. Only POST and PUT are provided for insert and update respectively. The mappings are used for these endpoints as well. Currently the endpoint uri must point to the local (meteor), collection name, rather than the remote, but the document sent should be the remote version.
One potentially important current limitation is a single collection on the remote equals a single collection locally.
It polls the remote for all changes after a certain date. It sends changes in realtime to specified endpoints on the remote. If the realtime change request fails, it will retry a certain set amount of times. Updates and inserts are done as full documents, rather than on a field by field basis.
ExternalID is required for the case where an insert was in the process when the application crashed or was shut down. Without remote external ID we cannot know for certain if the remote system successfully inserted the document.
It is also necessary when the remote side sends us back an insert call when we sent it first.
We need some way to query all records that have been deleted since a certain time. This isn't as important in the case where the remote is sending realtime changes. It also helps with associated records.
We avoid this for the rare case where a child record comes in before a parent record. This catch's that case, and should cause the system to correct itself on the next poll.
If we are pulling data we have already recieved such as an error occuring during poll, then we need to be sure that we avoid overwriting any changes on the local side. Passing the fetched data through the retry logic allows us to filter out records that have been updated on our side from the fetch, before updating the record on our side and overwriting local changes.
We normalize all external IDS to string.
- Migrate to differential:worker
- Allow configuration of inbound routes