openwhisk-package-cloudant icon indicating copy to clipboard operation
openwhisk-package-cloudant copied to clipboard

Specify doc id as parameter outside of doc body when creating doc via write action

Open tleyden opened this issue 8 years ago • 4 comments

I'm trying to build a sequence of actions where one action produces:

{
    "doc": {
        "IsTruncated": false,
        "Marker": null,
        "Users": [
            {
                "Arn": "arn:aws:iam::9798798:user/[email protected]",
                "CreateDate": "2016-01-11T23:49:40Z",
                "PasswordLastUsed": "2017-06-07T17:41:08Z",
                "Path": "/",
                "UserId": "ERXEAIDAHGJJK87878KKW",
                "UserName": "[email protected]"
            },
        ...
    ]
}

and the output is connected to a cloudant write action.

Everything works, however it creates a new unique doc id every time the action sequence is invoked, which isn't what I want in this case. The only way that I can tell to have it write to the same doc id is to modify the upstream action to produce:

{
    "doc": {
        "_id": "aws_user_list",
        "IsTruncated": false,
        "Marker": null,
        "Users": [
            {
                "Arn": "arn:aws:iam::9798798:user/[email protected]",
                "CreateDate": "2016-01-11T23:49:40Z",
                "PasswordLastUsed": "2017-06-07T17:41:08Z",
                "Path": "/",
                "UserId": "ERXEAIDAHGJJK87878KKW",
                "UserName": "[email protected]"
            },
        ...
    ]
}

It would be a "nice-to-have" option to be able to bind the doc id parameter to a cloudantdb write action so that when I call the action it will use that doc id, rather than having to include the _id parameter in the doc contents.

Actually I just realized this is assuming it's even possible to create an action based on an existing cloudant write action and bind extra parameters to it. I'm not sure how to do that, but I thought I remember reading that it was possible.

tleyden avatar Jul 04 '17 18:07 tleyden

The write action provides this feature: it will fetch the document by id, extract the revision, and use it to update the document in place (see https://github.com/apache/incubator-openwhisk-package-cloudant/blob/master/actions/database-actions/write-document.js#L34). To use this, use -p overwrite true if using the cli as in:

> wsk action invoke your.cloudant.binding/write -r \
-p dbname example \
-p doc '{"a":"hi", "_id": "8c22a2fe5b3bbe236da144544ac09920"}' \
-p overwrite 'true' 

@jasonpet why is this action called write instead of write-document to be consistent with the other actions in this package/

rabbah avatar Jul 05 '17 17:07 rabbah

@rabbah thanks, I just tried it and it worked. This ticket is asking for something slightly different though .. I was looking for a way to specify the doc id to write to outside of the doc body (via an explicit parameter)

tleyden avatar Jul 06 '17 05:07 tleyden

This is a script that I think does what you want - it uses "combinators" to forward the doc id around the middle action of the sequence. I'm using this for a write up on general limitations with sequences, how to work around them, and what we can do better.

The action sequence here is: read document from cloudant, translate it using watson services, and write back to cloudant (by updating the document in place).

#!/usr/bin/env bash

WSK='wsk'

PREFIX="howto"
PACKAGE_PROVIDER="/whisk.system"
DBNAME="example"

function bind() {
    set -e

    DB_USERNAME=${DB_USERNAME:?"DB_USERNAME should be set. This is the username for the Cloudant service."}
    DB_PASSWORD=${DB_PASSWORD:?"DB_PASSWORD should be set. This is the password for the Cloudant service."}

    XT_USERNAME=${XT_USERNAME:?"XT_USERNAME should be set. This is the username for the Translator service."}
    XT_PASSWORD=${XT_PASSWORD:?"XT_PASSWORD should be set. This is the password for the Translator service."}

   $WSK package bind $PACKAGE_PROVIDER/cloudant "${PREFIX}.cloudant" \
       -p username "$DB_USERNAME" \
       -p password "$DB_PASSWORD" \
       -p host "${DB_USERNAME}.cloudant.com" \
       -p dbname "$DBNAME"

    # configured to translate the field 'doc' in the input from 'en' to 'fr'
    $WSK package bind $PACKAGE_PROVIDER/watson-translator "${PREFIX}.translator" \
        -p username "$XT_USERNAME" \
        -p password "$XT_PASSWORD" \
        -p translateFrom 'en' \
        -p translateTo 'fr' \
        -p translateParam 'doc'

    # configured to forward (id,rev) around translator action
    $WSK package bind $PACKAGE_PROVIDER/combinators "${PREFIX}.combinators.translator" \
        -p '$ignore_certs' true\
        -p '$actionName' "${PREFIX}.translator/translator" \
        -p '$actionArgs' '["doc"]' \
        -p '$forward'    '["_id", "_rev"]'

    # configured to smash parameters together
    $WSK package bind $PACKAGE_PROVIDER/utils "${PREFIX}.utils" \
        -p '$fieldName' "doc"
}

function pipeline() {
    $WSK action update "${PREFIX}.cloudant.translator.pipeline" --sequence \
        "${PREFIX}.cloudant/read-document","${PREFIX}.combinators.translator/forwarder","${PREFIX}.utils/smash","${PREFIX}.cloudant/create-document"
}

function run() {
    $WSK action invoke -br "${PREFIX}.cloudant.translator.pipeline" -p docid "$1"
}

function createdb() {
    $WSK action invoke -br "${PREFIX}.cloudant/create-database" -p dbname "$DBNAME"
}

function createdoc() {
    echo $1
    $WSK action invoke -br "${PREFIX}.cloudant/create-document" -p dbname "$DBNAME" -p doc "$1"
}

function deletedoc() {
    $WSK action invoke -br "${PREFIX}.cloudant/delete-document" -p dbname "$DBNAME" -p docid $1 -p docrev $2
}

function getdoc() {
    $WSK action invoke -br "${PREFIX}.cloudant/read-document" -p dbname "$DBNAME" -p docid $1
}

function translate() {
    rm -f .input.txt
    echo $1 > .input.txt
    $WSK action invoke -br "${PREFIX}.translator/translator" -P .input.txt
    rm -f .input.txt
}

function deletedb() {
    $WSK action invoke -br "${PREFIX}.cloudant/delete-database" -p dbname "$DBNAME"
}

function cleanup() {
    $WSK package delete "${PREFIX}.cloudant"
    $WSK package delete "${PREFIX}.translator"
    $WSK package delete "${PREFIX}.combinators.translator"
    $WSK package delete "${PREFIX}.utils"
    $WSK action  delete "${PREFIX}.cloudant.translator.pipeline"
}

function usage() {
  echo "Usage $0 [--bind, --pipeline, --run, --createdb, --deletedb, --createdoc, --getdoc, --translate, --cleanup]"
  echo "The script assumes you have defined the following environment variables:"
  echo "   export XT_USERNAME=<translator service username>"
  echo "   export XT_PASSWORD=<translator service password>"
  echo "   export DB_USERNAME=<cloudant username - NOTE: this script wont work for an api key>"
  echo "   export DB_PASSWORD=<cloudant password>"
  echo ""
  echo "Example how to use this script:"
  echo "  --bind        creates the package bindings for Translator and Cloudant to use those actions"
  echo "  --pipeline    creates the pipeline: read document by id -> translate it -> write document to cloudant"
  echo "  --run         will run the pipeline, requires as argument a <document id>"
  echo "  --cleanup     delete bindings and the main pipeline"
  echo ""
  echo ""
  echo "The script provides some helpers:"
  echo "  --createdb    creates database in the Cloudant account (the DBNAME is hardcoded in this script)"
  echo "  --deletedb    drops database (the DBNAME is hardcoded in this script)"
  echo "  --createdoc   writes a document to Cloudant (the DBNAME is hardcoded in this script)"
  echo "  --getdoc      gets a document from Cloudant by <id> (the DBNAME is hardcoded in this script)"
  echo "  --transalate  runs translator for a given document input (input must be JSON and hardcoded to define a <doc> field in this script)"
}

case "$1" in
--bind )
bind
;;
--pipeline )
pipeline
;;
--run )
shift
run "$@"
;;
--createdb )
createdb
;;
--deletedb )
deletedb
;;
--createdoc )
shift
createdoc "$@"
;;
--deletedoc )
shift
deletedoc "$@"
;;
--translate )
shift
translate "$@"
;;
--getdoc )
shift
getdoc "$@"
;;
--c* )
cleanup
;;
* )
usage
;;
esac

rabbah avatar Jul 06 '17 14:07 rabbah

Thanks! That's really helpful, I hadn't seen the /whisk.system/combinators package yet.

tleyden avatar Jul 06 '17 14:07 tleyden