0

I have an Eve app publishing a simple read-only (GET) interface. It is interfacing a MongoDB collection called centroids, which has documents like:

[
{
  "name":"kachina chasmata",
  "location":{
    "type":"Point",
    "coordinates":[-116.65,-32.6]
  },
  "body":"ariel"
},
{
  "name":"hokusai",
  "location":{
    "type":"Point",
    "coordinates":[16.65,57.84]
  },
  "body":"mercury"
},
{
  "name":"cañas",
  "location":{
    "type":"Point",
    "coordinates":[89.86,-31.188]
  },
  "body":"mars"
},
{
  "name":"anseris cavus",
  "location":{
    "type":"Point",
    "coordinates":[95.5,-29.708]
  },
  "body":"mars"
}
]

Currently, (Eve) settings declare a DOMAIN as follows:

crater = {
    'hateoas': False,
    'item_title': 'crater centroid',
    'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
    'datasource': {
        'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
    }
}

DOMAIN = {
    'centroids': crater,
}

Which will successfully answer to requests of the form http://hostname/centroid/<body>/<name>. Inside MongoDB this represents a query like: db.centroids.find({body:<body>, name:<name>}).

What I would like to do also is to offer an endpoint for all the documents of a given body. I.e., a request to http://hostname/centroids/<body> would answer the list of all documents with body==<body>: db.centroids.find({body:<body>}).

How do I do that?

I gave a shot by including a list of rules to the DOMAIN key centroids (the name of the database collection) like below,

crater = {
...
}

body = {
    'item_title': 'body craters',
    'url': 'centroids/<regex("[\w]+"):body>'
}

DOMAIN = {
    'centroids': [crater, body],
}

but didn't work...

AttributeError: 'list' object has no attribute 'setdefault'
Brandt
  • 5,058
  • 3
  • 28
  • 46
  • Have you tried `http://hostname/centroids?where={"body": }`? – gcw Jul 17 '19 at 16:08
  • @gcw Yes, indeed that works out of the box if I keep the default settings, _i.e._, `DOMAIN = {'centroids': {}}`. That being the case, I could use `http://hostname/centroids?where={"body":"mars","name":"cañas"}`. The key point here is that I want to offer to my user a clean interface, made by simple, db agnostic path endpoints. For instance: `http://hostname/centroids/mars` or `http://hostname/centroids/mars/cañas`. – Brandt Jul 18 '19 at 12:49

1 Answers1

0

Got it!

I was assuming the keys in the DOMAIN structure was directly related to the collection Eve was querying. That is true for the default settings, but it can be adjusted inside the resources datasource.

I figured that out while handling an analogous situation as that of the question: I wanted to have an endpoint hostname/bodies listing all the (unique) values for body in the centroids collection. To that, I needed to set an aggregation to it.

The following settings give me exactly that ;)

centroids = {
    'item_title': 'centroid',
    'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
    'datasource': {
        'source': 'centroids',
        'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
    }
}

bodies = {
    'datasource': {
        'source': 'centroids',
        'aggregation': {
            'pipeline': [
                {"$group": {"_id": "$body"}},
            ]
        },
    }
}

DOMAIN = {
    'centroids': centroids,
    'bodies': bodies
}
  • The endpoint, for example, http://127.0.0.1:5000/centroid/mercury/hokusai give me the name, body, and coordinates of mercury/hokusai.
  • And the endpoint http://127.0.0.1:5000/bodies, the list of unique values for body in centroids.

Beautiful. Thumbs up to Eve!

Brandt
  • 5,058
  • 3
  • 28
  • 46