Reputation: 5102
My Backbone app is communicating with a REST API built on top of MongoDB, so my objects' "natural" ids are really MongoIDs
. When serialized into JSON, they look like:
"_id":{"$id":"505099e998dee4db11000001"}
The Backbone documentation mentions that you can specify another name than id
for your Backbone model's id attribute (using idAttribute
), however, as MongoIDs' string representations are nested, just using idAttribute: '_id'
doesn't help in consuming JSON directly.
Is there a way around this, other than rewriting attributes on the server side?
Update:
Here's what I'm doing server-side:
$m = new Mongo();
$posts = $m->mydatabase->posts->find();
$out = array();
foreach ($posts as $post) {
$out[] = $post;
}
echo json_encode($out);
I know I could do something like $post['id'] = (string) $post['_id']; unset($post['_id']);
but it is precisely what I'm looking to avoid!
Upvotes: 12
Views: 3030
Reputation: 2055
Your PHP code is the REST API that Backbone will interact with, so it should handle the abstraction of Mongo's complex _id
property to the simple id
string you're looking for. That is definitely the API's job.
Backbone, or any other consumer of your API, should NOT know anything about Mongo or _id
.
Why?
Because if you were to switch from Mongo to some other Db where there is no _id
, then your API is still good because all that was ever exposed was id
, which is super generic. So you're original idea was actually the best idea (although you'd want to abstract that piece of code into something that can be reused for all models, not just posts).
Upvotes: 0
Reputation: 71
It's better to do the conversion in the browser so you move the computation off from the server. So you'd want to create a base MongoModel, and then you can extend from MongoModel instead of Backbone.Model.
MongoModel = Backbone.Model.extend({
// this handle conversion between the mongo's _id and backbone id
// this is best done on the client side to alleviate server load
//_id : { "$oid" : ... } <--> id
parse : function (response) {
response.id = response._id.$oid;
delete response._id;
return response;
},
toJSON : function () {
var
json = Backbone.Model.prototype.toJSON.apply(this);
json._id = {'$oid':json.id};
delete json.id;
return json;
}
});
Upvotes: 5
Reputation: 1053
Looking at various suggested options I found the easiest would be to do what you want to avoid. (Using parse does work though)
$m = new Mongo();
$posts = $m->mydatabase->posts->find();
$out = array();
foreach ($posts as $post) {
// populate an id field
$post['id']=$post['_id']->{'$id'},
$out[] = $post;
}
echo json_encode($out);
Keeping $post['_id']
if you want your model to send it back when syncing.
I prefer correcting the API as more clients might want to connect to it.
Upvotes: 3
Reputation: 2138
In Ruby I'm able to do the following:
items.find.to_a.map do |item| frombsonid(item) end.to_json def frombsonid(obj) obj.merge({'_id' => obj['_id'].to_s}) end
and when you get the data back, you can convert the string to BSON::ObjectId
def tobsonid(id) BSON::ObjectId.fromstring(id) end
So the idea is to replace _id in each item with a string version of BSON::ObjectId
In backbone you can add
idAttribute: "_id",
In PHP you will use different syntax and methods, but I believe it's quite possible to replicate this.
Upvotes: 0
Reputation: 8581
This sounds like a good example for parse()
.
Since your Mongo JSON ends up sending:
"_id":{"$id":"505099e998dee4db11000001"}
Why not use the Backbone parse to properly namespace the incoming data?
parse: function(response) {
response.id = response._id['$id'];
delete response._id;
return response;
}
Or something like this. Similarly, since Backbone will be sending the id as JSON with 'id', your server might take that and "translate" it the other way.
If you want to use a different id attribute, _id
, you would just replace the above parse with this code:
idAttribute: '_id',
parse: function(response) {
response._id = response._id['$id'];
return response;
}
Whatever works best for you. :-)
Upvotes: 15