angularjsravendbravendb-http

How to retrieve the ID as part of an index with AngularJS and RavenDB?


I'm following the tutorials from Pro AngularJS and I'm retrieving a few products from the HTTP API. Instead of using Deployd, I wanted to work with RavenDB instead.

Following the advice at this post, I can use the dynamic indexes to get all of the products like this:

http://localhost:8080/databases/Catalogue/indexes/dynamic/Products

This results in the JSON like this:

{
  Results: [
  {
    name: "Kayak",
    description: "A boat for one person",
    category: "Watersports",
    price: 275,
    @metadata: {
        Raven-Entity-Name: "Products",
        @id: "products/1",
        Temp-Index-Score: 0.882217,
        Last-Modified: "2014-10-07T20:26:31.4436923Z",
        Raven-Last-Modified: "2014-10-07T20:26:31.4436923",
        @etag: "01000000-0000-0001-0000-000000000001"
    }
},
{ ... }

And a sample of AngularJS would result in this:

 $http.get(dataUrl)
      .success(function(result) { 
         $scope.products = result.Results;
      });

When using this approach, the ID is stored as product["@metadata"].["@id"], which is a bit difficult to bind on the affected pages, instead of product.id. When trying to display the ID, post the ID back for deletion from a basket, you would do something like:

<table>
   <tr ng-repeat="product in products">
      <td>{{product["@metadata"]["@id"]}}</td>
      <!-- other columns -->
   </tr>
</table>

An alternative approach to get around this is to basically create the ID dynamically, like this:

   $http.get(dataUrl)
        .success(function (result) {

            var localResults = [];

            for (var i = 0; i < result.Results.length; i++) {
                localResults.push(result.Results[i]);
                localResults[i].id = result.Results[i]["@metadata"]["@id"];
            };

            $scope.data = {
                products: localResults
            };
        });

I have tried creating indexes that explicitly call out the ID, so for example:

// Index: Products/All
from product in docs.Products
select new {
   id = product.Id,
   name = product.Name,
   category = product.Category,
   description = product.Description,
   price = product.Price
}

But the document is in exactly the same format as before.


My question is this:

Is it possible for RavenDB to emit just the fields from the document, even through a specific index or transformer that a) ignores the metadata or b) adds the ID explicitly as a field.


Solution

  • Well to the first part of your question an index does not change what the results look like only how you query the data. So creating an index with an "id" field would not do what you want. If you want to change the results you need to use a transformer. So in your case you would create a transformer like:

    from product in results
    select new
    {
       id = product.Id,
       name = product.Name,
       category = product.Category,
       description = product.Description,
       price = product.Price
    }
    

    than you would need to tie the transformer to your index. So your url would look like this:

    http://localhost:8080/databases/Catalogue/indexes/dynamic/Products?resultsTransformer=ProductTransformer
    

    Hope that helps.

    As an alternative suggestion if you didn't want use the transformer. In angular you could do something like this:

    <table>
       <tr ng-repeat="product in products">
          <td>{{getId(product)}}</td>
          <!-- other columns -->
       </tr>
    </table>
    

    Then on your $scope:

    $scope.getId = function(product){
        return product["@metadata"]["@id"];
    }