How to use array as id in the backbone - backbone.js

In the backbone, I have a json structure from the web server like this.(Note, I will only receive a bunch of documents, so not for restful service)
{ 'stations':[station1,station2], 'geo':[lat1,lng1,lat2,lng2 ....]}, in which 'stations' array has only two numbers who represents the bus stations number, while 'geo' represents the intermediate geolocation points between the two stations. and usually in the application, I could get the stations array in whatever array[station1,station2] or [station2,station1], and then I use this stations array as a unique id to get the 'geo' array - the intermediate geo loation points.
For example, {'stations':[38306,38304],'geo':[ 53.21579073715244,-2.8958864745734445,53.26019,-2.9422970000000532]}, meaning I have two stations numbered 38306 and 38304, and 4 length array 'geo' representing 2 geo points.
window.stanoxPoints = Backbone.Model.extend({
defaults:{
"stations":new Array(),
"points":new Array()
}
});
window.stanoxPointsCollection = Backbone.Collection.extend({
model: stanoxPoints,
url:"http://localhost:8080/geo",
});
var stanoxCollection = new stanoxPointsCollection();
stanoxCollection.fetch({
success:function(collection,response){
console.log('fetch the data success');
collection.each(function(data){
console.log(data.get('stations')+" "+data.get('points'));
})
},
error:function(collection, response){
}
})
so I design the model simply in this way above, and fetch the data using the collection, but when I want to query the data, there is something wrong,
stanoxCollection.get([38201,38202]) //undefined
My question is if I only use the 'station' array to get the 'geo' array, how can I make it the 'station' as id or index in the backbone model, and no matter what the order of the array 'stations', e.x [station1,station2] or [station2,station1] it can get me the array of geo points, only when stations array order is reversed, the order of geo array is reversed too.
Now I have tried to idAttribute: 'stations', so since original id is [38201,38202], so
console.log('fetch get by id', stanoxCollection.get([38201,38202]).get('points'));// works
console.log('fetch get by id', stanoxCollection.get([38202,38201])); // doesn't work for reversed array as id
is there way to deal with it?

Related

MongoDb subdocument array populate (via Mongoose ORM) : Does it maintain array order when populate is called

Suppose I have 2 Schema's in Mongoose that look like this:
var movieSchema = mongoose.Schema({
name: String,
type: String
});
var moviePlaylistSchema = mongoose.Schema({
name: String,
movies: [{type: mongoose.Schema.Types.ObjectId, ref: 'Movie'}]
});
var Movie = mongoose.model('Movie', movieSchema);
var MoviePlaylist = mongoose.model('MoviePlaylist', moviePlaylistSchema);
If a query was made along the following lines:
MoviePlaylist.find({}).populate('movies').exec(function(err, res) {
if (err) console.log('err', err);
else {
console.log('res', res);
res.forEach(function(elem, index) {
console.log('elem.name', elem.name);
});
}
});
Would the order of the elements in the array be maintained? The objective here is to allow the user to maintain a playlist order of their movies. If, when the "populate" method fires, the array order of Movie object Ids is not maintained, then this will not serve my purpose. Hence thought I'd ask someone who is more knowledgeable in this area.
If this works, then I have another task which is allowing the user to change the order of movies in the playlist, which should be straight forward by allowing the movie object id index to be swapped in the array.
Thanks for your help in advance.
MongoDB will keep the order of the array, much like an array in any programming language.
You can view the BSON/JSON spec for reference which highlights that the array must contain integer values for keys, and be maintained in ascending numerical order.
Additionally, the Mongoose populate on an array works by calling Model.populate via forEach on each element of the array. This modifies the array in place, hence the order is preserved. You can see the relevant source code here.

Angular ngRepeat not preserving order of Firebase priority items?

Pretty new to Angular & Firebase here, but noticed an odd behavior querying and presenting ordered data that isn't addressed anywhere else yet...
I'm pushing data to firebase and setting priority with a descending negative value so that newest data is on top of the list.
When retrieving the ref with child_added events, I can confirm the data is arriving in the correct order; however, when used with ngRepeat, the data is somehow getting reversed (newest data appears on bottom of ngRepeat list).
If I use something like .append() the data is correctly ordered. But would rather do it the 'Angular' way with ngRepeat.
// example html binding
// ====================================
<ul>
<li ng-repeat="(itemID, item) in list">{{itemID}}</li>
</ul>
// example controller code
// ====================================
var laApp = angular.module('laApp', ['firebase']);
laApp.controller('laAppCtrl', function ($scope, $timeout){
var ref = new Firebase('https://ngrepeatbug.firebaseio.com');
$scope.pushPriority = function(){
var uid = new Date().getTime();
var priority = 0 - uid;
// set with -priority so newest data on top
ref.push().setWithPriority(uid, priority);
}
$scope.list = {};
ref.orderByPriority().on('child_added', function(snap){
$timeout(function(){
var snapID = snap.key();
var snapVal = snap.val();
//repeat method
$scope.list[snapID] = snap.val();
//append method
$('ul.append').append("<li>" + snapVal + "</li>")
})
})
});
Pen comparing ngRepeat and append methods:
http://codepen.io/juddam/pen/dIiLz
I've read other solutions that either convert the $scope.list object into an array that is then used with $filter or reversing order on client, but this defeated the whole purpose of storing data by priority and having a straightforward method for querying and presenting ordered data.
Know orderByPriority is new to firebase v2.0 so wondering if bug or am I missing something obvious?
You're adding the children to an object with this:
$scope.list[snapID] = snap.val();
Even though this looks like you're adding to an array, you're actually adding to a regular object. And as #ZackArgyle says in his comment: the keys in an object have no guaranteed order.
If you want to maintain the order of the items, you should push them into an array.
$scope.list.push(snap.val());
This adds them with numeric indices, which will maintain their order.
If you want to both maintain the order of the items and their key, you will have to manage them in an array.
$scope.list.push({ $id: snap.key(), value: snap.val() });
That last approach is an extremely simplified version of what AngularFire does when you call $asArray().

Select users not in array of pointers

Using Parse.com and its Cloud code, I want to fetch users that are not in array of users.
...
var query = new Parse.Query(Parse.User);
query.notContainedIn("objectId", request.object.get("recipients"));
...
query.find().then(
function(results) {
console.log("# of users:" + results.length);
},
function(error) {
console.error(error)
}
);
The constraint notContainedIn doesn't seem to work, all users are returned, not just the ones not contained in the recipients array coming as part of the request object.
The recipients array in REST request is defined like this
"recipients":[
{"__type":"Pointer","className":"_User","objectId":"qwerty1234"},
{"__type":"Pointer","className":"_User","objectId":"asdfgh1234"}]
The data I get as part of the request is ok, because e.g. request.object.get("recipients")[0].id returns the qwerty1234 value.
What am I doing wrong here?
You are asking parse to compare the objectId to an array of pointers. This would work fine if the column was a Pointer to a User, but you're using just the ID.
The easy solution is to map or extract the ID from the array of pointers, e.g.
// at the top, so you can use the Underscore library
var _ = require('underscore');
// ...
// in your Cloud function
var query = new Parse.Query(Parse.User);
// _.pluck() creates an array of a property from each object in the parent array
var recipientObjectIds = _.pluck(request.object.get('recipients'), 'objectId');
query.notContainedIn('objectId', recipientObjectIds);

Backbone.js: Grabbing the length of a collection for use with random number

I want to grab the length of a collection to use in a random number generator. I want a view that shows one model of the collection, randomly generated. I'm using coffeescript, btw
So far I've tried stuff like
#collection.fetch
data:
id: Math.floor((Math.random()*#length)+1)
which won't work because the length isn't there until after it's fetched... I've tried a couple of other methods, such as grabbing after fetching, but length is always zero.
Anyone give me an idea of how to do this?
edit: javascript for those who can't read coffee
this.collection.fetch({
data: {
'id': Math.floor((Math.random() * length) + 1)
}
});
I had same task in the past. I used underscore _.sample method.
Please try _.sample(collection) it will return random model from collection or even better _.sample(collection, 4) for 4 random models.
According to the Backbone manual :
Backbone.Collection
Collections are ordered sets of models
So what you need in your application is actually a random model from your server database. According to your API, you need to get the count of your records in your server and then get a random model of one of the records. If you are the developer of your Serverside API there is a way to do that with one connection, otherwise you can do something like this :
class randomModel extends Backbone.Model
// Assuming 'GET' /api/model/100 will get record No. 100
urlRoot: '/api/model'
// ... in your document ready
$ () ->
model = null
// Assuming 'GET' /api/count, will return JSON string with your records count
$.getJSON '/api/count', (response) =>
model = new randomModel id: (Math.random()*response.count)+1
model.fetch()
console.log model
Pretty much that's what I would use in your case. Another method is to populate the whole collection and get the random model after it is populated ( you save one request ), by doing :
collection.fetch() // get's all models
collection.get (Math.random()*collection.length)+1

Object Arrays in Azure Table Storage

I'm trying to build a simple Mobile Service on Azure and I'm having some problems while inserting my information. Right now, I've got two classes in my model, User and Car. A User has an AccountID, a Name (all these Strings) and an Array of Car. A Car has a Plate, a Color and a Model (all these Strings).
I'm serializing the User object correctly to JSON and when I try to do request.execute() it throws an error that says "The value of property 'cars' is of type object which is not supported". I know that only string, number, bool and date are suppported.
What I'd like to do, is to have two separate tables, one for users and another one for cars, and somehow establish a relationship between them. This is the script I've written so far
function insert(item, user, request) {
if(item.accountID !== user.userId){
request.respond(statusCodes.UNAUTHORIZED,
"Unauthorized user");
} else {
if(item.cars.length){
var tableCars = tables.getTable('cars');
populateTable(tableCars, request, item.cars);
}
request.execute();
}
}
function populateTable(table, request, array){
var index = 0;
var insertNext = function(){
if(index < array.length){
var toInsert = array[index];
table.insert(toInsert, {
success: function(){
index++;
insertNext();
}
});
}
};
insertNext();
}
At this point I've got several problems. If I leave it this way, it crashes because items.cars is an Array of Car (an object for JS) but I do want to have here some kind of id to find cars that belong to this User in its table. Maybe I should add some kind to 'owner' to Car, but I'm not sure, my knowledge of databases is somehow poor.
What should I do?
Azure table storage does not support relational tables. Furthermore, ATS does not support storing of strongly typed child objects as a part of parent entities. ATS is a key-value entity-based table storage. It only supports basic data types like string, date, double, boolean, etc.
If you want to store complex objects in ATS (complex, meaning objects that contain other objects), it is suggested that you should serialize the child objects as strings rather then objects, when storing the data and de-serialize the strings back into objects during retrieval.
Alternatively, you can get very fancy with your Row/PartitionKeys and store Parent object and child objects as different entities within the same PartitionKey - and when reading the values back, reconstruct the hierarchy.

Resources