Fetch Backbone Collection by Model IDs list - javascript

I have a REST API serving a few URLs:
/rest/messages
provides all messages. A message is a JSON/Backbone Model
{
title: 'foo',
body : 'bar'
}
To get a single message I have:
/rest/messages/:id
Is it possible to fetch a Backbone Collection using message IDs array? I don't want the whole message list, but just a few messages I specify by ID.
I could fetch Models one-by-one and fill up the Collection, but I'm wondering if Backbone has a cleaner way to do this.
Thanks

According to documentation, you can pass ajax options to the fetch call. So, you can pass ids as data attribute to the fetch call being done and based on it, return the respective models from the server.
For example (when doing fetch),
collection.fetch({
data : {
message_ids : [1, 3, 5] // array of the message ids you want to retrieve as models
}
})
This message_id array will be accessible as parameters (not sure of the name in your case) in the server code being executed at /rest/messages, from there you can return only specific models based on ids you receive as message_ids. The only thing you need is, client side must be aware of the ids of all the message models it needs.
You can use any data structure instead of array to send message_ids.

The url property of collection reference to the collection location on the server. When you use fetch, backbone uses that url.
The url property can be also a function that returns the url. So you can do something like that:
var ids = [1,2,3]
var messages = new MessegecCollection();
messages.url = function() {
return "/rest/messages/"+ids.join("-"); //results "/rest/messages/1-2-3"
}
messages.fetch();
You can also create a method in your collection that generated and set the url, or even fetchs a set of models.
Now all you have to do is to support this url: /rest/messages/1-2-3
Hope this helps!

Related

Restangular: getList(), then get related information

I am trying to wrap my head around how this would be done.
Get a list of "Creations".
"Creations" list returns an ID of the "Author" of that creation.
Automatically do another Restangular call to grab that Authors information and relate it to the object returned by the first getList of creations.
Restangular.all('creations').getList({
limit: 5
}).then(function(creations) {
$scope.creations = creations;
// returns a list of Objects for each creation with one parameter being author:id (author:1,2,3, etc)
// THEN GET INFORMATION ABOUT EACH CREATION'S AUTHOR
// Restangular.one('users', creations.author).get().......?
});
Is there a better way of doing this so that in my view I can access something like $scope.creations.authorObject...

Ember data - One model, two endpoints

In ember data, if you want to fetch the collection of a model, it's convention to use this:
this.store.findAll('order');
or with a filter, this:
this.store.find('order', {shopId: 63});
So you pass the model name, and Ember-data will build the URL for you, which would look something like (depending on your adapter):
GET /api/orders
GET /api/orders?shopId=63
So this does two things
Build the URL to fetch data from the api
Map the collection as JavaScript objects, using the model that you passed as 1st argument
But what if I want to fetch orders from two URLs; /api/orders and /api/new_orders ?
The first one will work as usual: this.store.findAll('order'), but is there a way to override the api path that you fetch from?
Maybe something like this.store.find('order', {path: '/new_orders'})?
So that I can end up with a collection of objects modelled with my order model, but fetched from a different route
You need to have a rest adapter for this store and override the findAll method. The default implementation is as such
findAll: function(store, type, sinceToken) {
var query, url;
if (sinceToken) {
query = { since: sinceToken };
}
url = this.buildURL(type.modelName, null, null, 'findAll');
return this.ajax(url, 'GET', { data: query });
}
buildUrl will return a proper endpoint for your first url. you could then parse this url and modify it to make a second request with the same data, but with to your second endpoint. Than you could merge the responses or use them separately.
Reference: https://github.com/emberjs/data/blob/v1.13.5/packages/ember-data/lib/adapters/rest-adapter.js#L398

Backbone Sub-Collections & Resources

I'm trying to figure out a Collection/Model system that can handle retrieving
data given the context it's asked from, for example:
Available "root" resources:
/api/accounts
/api/datacenters
/api/networks
/api/servers
/api/volumes
Available "sub" resources:
/api/accounts/:id
/api/accounts/:id/datacenters
/api/accounts/:id/datacenters/:id/networks
/api/accounts/:id/datacenters/:id/networks/:id/servers
/api/accounts/:id/datacenters/:id/networks/:id/servers/:id/volumes
/api/accounts/:id/networks
/api/accounts/:id/networks/:id/servers
/api/accounts/:id/networks/:id/servers/:id/volumes
/api/accounts/:id/servers
/api/accounts/:id/servers/:id/volumes
/api/accounts/:id/volumes
Then, given the Collection/Model system, I would be able to do things like:
// get the first account
var account = AccountCollection.fetch().first()
// get only the datacenters associated to that account
account.get('datacenters')
// get only the servers associated to the first datacenter's first network
account.get('datacenters').first().get('networks').first().get('servers')
Not sure if that makes sense, so let me know if I need to clarify anything.
The biggest kicker as to why I want to be able to do this, is that if the
request being made (ie account.get('datacenters').first().get('networks'))
hasn't be made (the networks of that datacenter aren't loaded on the client)
that it is made then (or can be fetch()d perhaps?)
Any help you can give would be appreciated!
You can pass options to fetch that will be translated to querystring params.
For example:
// get the first account
var account = AccountCollection.fetch({data: {pagesize: 1, sort: "date_desc"}});
Would translate to:
/api/accounts?pagesize=1&sort=date_desc
It is not quite a fluent DSL but it is expressive and efficient since it only transmits the objects requested rather than filtering post fetch.
Edit:
You can lazy load your sub collections and use the same fetch params technique to filter down your list by query string criteria:
var Account = Backbone.Model.extend({
initialize: function() {
this.datacenters = new Datacenters;
this.datacenters.url = "/api/account/" + this.id + '/datacenters';
}
});
Then from an account instance:
account.datacenters.fetch({data: {...}});
Backbone docs on fetching nested models and collections

How to only use a certain dict from a get request with Backbone?

I have exposed to Backbone an API that returns user profiles with this structure:
{id: 1, following: {...}}. I only want to use the dictionary inside of the "following" attribute. How would I do that? Right now, I have a model with a URL to the API. I have a collection that uses this model. I do a fetch() on the collection, but I only want to use the dictionary inside of "following".
You should use parse to extract what you want from the the response:
parse model.parse(response)
parse is called whenever a model's data is returned by the server, in fetch, and save. The function is passed the raw response object, and should return the attributes hash to be set on the model.
So you'd want something like this in your model:
parse: function(response) {
return response.following;
}

How do I get a model from a Backbone.js collection by its id?

In my app, everything I do with data is based on the primary key as the data is stored in the database. I would like to grab a model from a collection based on this key.
Using Collection.at() requires the array index, Collection.getByCid() requires the client ID that backbone randomly generates.
What is the best way to grab the model I want from the collection with the given id value? I figure the worst I could do would be to iterate over each item, .get('id'), and return that one.
Take a look at the get method, it may be of some help :)
http://backbonejs.org/#Collection-get
get collection.get(id)
Get a model from a collection, specified by an id, a cid, or by passing in a model.
If your data requires you to use a different kind of key or a set that doesn't mesh well with at(), getByCid() or get(), there is also where(). Something like this might work:
window.lib = new Library;
window.lib.fetch([
success: function(model, response) {
console.log(window.lib.where({'BookID':488, 'Rev':2, 'Status':'Active'});
}
});

Categories

Resources