MarvinAPI icon indicating copy to clipboard operation
MarvinAPI copied to clipboard

Basic examples for CouchDB API use in Marvin

Open jbriales opened this issue 3 years ago • 4 comments

Hi! Would it be possible to add some very basic examples on how to use the CouchDB API for some basic actions like just getting an item by id? The docs in https://github.com/amazingmarvin/MarvinAPI/wiki/Database-Access do not seem enough to get started here. Maybe because I've never used CouchDB, but looking at the linked CouchDB API documentation for a long while, I have no idea where to even put the databaseUri, databaseUser and databasePassword parameters. I'm sure a bunch of examples would be very valuable for any newcomer here.

Thanks!

jbriales avatar Nov 21 '20 13:11 jbriales

@jbriales I also found the Database Access page a bit lacking, I think it definitely does assume a familiarity with CouchDB. After some poking around in the CouchDB documentation this weekend, I did manage to make some progress.

First off, the documentation references databaseUri, databaseUser and databasePassword, but when you click the link to see your credentials this is references to syncServer and syncDatabase (which combine to make the URI), syncUser and syncPassword, so this is what I'll reference as they seem to be aliases for the same information.

So to perhaps answer the most basic question about how the parameters work, I seemed to land on the following. If you want to access the root of your Marvin database as described in the CouchDB documentation here, you're going to make a GET request to syncServer/syncDatabase which will be your database's URI. As part of this request, you need to use basic HTTP auth to pass syncUser as your username and syncPassword as your password. If successful, you should be getting a 200 response instead of a 401.

Now the answer you received in your other issue #3 this is possible via the /api/doc endpoint. So if you're able to make the previous request, you'd just make a GET request to syncServer/syncDatabase/<id_of_task> where <id_of_task> is just the numeric value you found following _id=.

Hope this helps!

brendanshoe avatar Mar 08 '21 21:03 brendanshoe

Here's a code snippet Mark shared with me when I requested an example some time ago. He suggested using PouchDB

It will look something like this:

const core = require("pouchdb-core");
const idb = require("pouchdb-adapter-idb");
const websql = require("pouchdb-adapter-websql");
const http = require("pouchdb-adapter-http");
const replication = require("pouchdb-replication");

let PouchDB = core.default || core;
PouchDB = PouchDB.plugin(idb.default || idb);
PouchDB = PouchDB.plugin(websql.default || websql);
PouchDB = PouchDB.plugin(http.default || http);
PouchDB = PouchDB.plugin(replication.default || replication);

const db = new PouchDB(syncDatabase);
const remoteUrl = `https://${syncUser}:${syncPassword}@${host}/${syncDatabase}`;
const remote = new PouchDB(remoteUrl, { skipSetup: true });
db.sync(remote)
.on("complete", () => {
db.query(...);
});

dmrd avatar May 16 '21 20:05 dmrd

I was trying to use the CouchDB API to pull my daily Events using Pipedream, so I had to figure this out, for Events at least. Here are my notes:


$ curl  -X GET --silent https://couchDbUsername:couchDbPassword@couchDbServer/couchDbDatabase/_design_docs/ # get the available docs
{
  "total_rows": 6,
  "offset": 6,
  "rows": [
    {
      "id": "_design/CategoriesAndOpenProjects",
      "key": "_design/CategoriesAndOpenProjects",
      "value": {
        "rev": "3-a1f69df663948aa9b5c4b355ba9aaafc"
      }
    },
    {
      "id": "_design/EventsByStart",
      "key": "_design/EventsByStart",
      "value": {
        "rev": "3-5a8051f0ca576dc7734d44e2d336a730"
      }
    },
    {
      "id": "_design/OpenTasksProjectsOnDayDueDate",
      "key": "_design/OpenTasksProjectsOnDayDueDate",
      "value": {
        "rev": "3-6bc4c8ebf0e02b686bb3bbc665741456"
      }
    },
    {
      "id": "_design/TasksByDayAndTime",
      "key": "_design/TasksByDayAndTime",
      "value": {
        "rev": "3-b05585da8520836bb23c742b2465a50a"
      }
    },
    {
      "id": "_design/TimeBlocksByDate",
      "key": "_design/TimeBlocksByDate",
      "value": {
        "rev": "3-1af512abe6bf8bcdf1bc6e61bd5673fb"
      }
    },
    {
      "id": "_design/app",
      "key": "_design/app",
      "value": {
        "rev": "1-9aeebdb8b1e555b46a4d2efee445ee16"
      }
    }
  ]
}

In my case I wanted EventsByStart, which I queried as follows to find out if there was a preconfigured view:

$ curl -X GET --silent 'https://couchDbUsername:couchDbPassword@couchDbServer/couchDbDatabase/_design/EventsByStart' | jq . # query for the available views for the EventsByStart

{
  "_id": "_design/EventsByStart",
  "_rev": "3-5a8051f0ca576dc7734d44e2d336a730",
  "language": "query",
  "views": {
    "98227457bcec99e5188d9aa0def2c4af5ed7ad28": {
      "map": {
        "fields": {
          "db": "asc",
          "start": "asc"
        },
        "partial_filter_selector": {
          "db": {
            "$eq": "Events"
          }
        }
      },
      "reduce": "_count",
      "options": {
        "def": {
          "fields": [
            "db",
            "start"
          ],
          "partial_filter_selector": {
            "db": "Events"
          }
        }
      }
    }
  }
}

That gave me the name of the view (98227457bcec99e5188d9aa0def2c4af5ed7ad28). Now to query the events I want, in this example for 2023-10-18:

$ curl "https://couchDbUsername:couchDbPassword@couchDbServer/couchDbDatabase/_design/EventsByStart/_view/98227457bcec99e5188d9aa0def2c4af5ed7ad28?startkey=%5B%22Events%22,%222023-10-18T00:00:00.000Z%22%5D&endkey=%5B%22Events%22,%222023-10-18T23:59:59.999Z%22%5D&reduce=false&include_docs=true" | jq .

{
  "total_rows": 385,
  "offset": 273,
  "rows": [
    {
      "id": "e9im6r31d5miqs35e9pmurj1dgmn6ubecct6aeb9dkr74cphcgqmqqbhdth6kpb4ddn3ct1hchhm8sbe6pq36pj4ddmmqe3fc8sm8q3jd9ln8q396ss6uqhocdo6idpke5l30pb8d4r30s1j6ph3iq1m61mmkcj565om8r38dkp76sjbchk6iqpge9l3ap9pd4rmarr2cdi6gqbe71h6kcr4ehmmkqr868ojid9m6lkmss9o70qj2d39dgo3kc8",
      "key": [
        "Events",
        "2023-10-18T13:00:00.000Z"
      ],
      "value": null,
      "doc": {
        "_id": "e9im6r31d5miqs35e9pmurj1dgmn6ubecct6aeb9dkr74cphcgqmqqbhdth6kpb4ddn3ct1hchhm8sbe6pq36pj4ddmmqe3fc8sm8q3jd9ln8q396ss6uqhocdo6idpke5l30pb8d4r30s1j6ph3iq1m61mmkcj565om8r38dkp76sjbchk6iqpge9l3ap9pd4rmarr2cdi6gqbe71h6kcr4ehmmkqr868ojid9m6lkmss9o70qj2d39dgo3kc8",
        "_rev": "1-c4fc4d4dfc391e3552ec5b04782a64a9",
        "createdAt": 1697644685389,
        "title": "✅ 📧 Morning Catch Up",
        "start": "2023-10-18T13:00:00.000Z",
        "length": 1800000,
        "isAllDay": false,
        "parentId": "unassigned",
...

Note that I truncated the output to hide the rest of my events...

Hope this helps the next person!

muness avatar Oct 19 '23 02:10 muness

The /_find endpoint seems even more useful. Here's an example POST query to get Events (you'll need the Authorization header to go with it):

{
"selector": {
 "db": "Events",
 "start": { 
   "$gte": "2023-10-18",
  "$lte": "2023-10-25T23:59:59.999Z"
  }
},
"fields": [
"title",
"start",
"length",
"parentId",
"isAllDay",
"calId",
"note",
"calData"
]
}

muness avatar Oct 23 '23 19:10 muness