Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Nano: The official Apache CouchDB library for Node.js

License

NotificationsYou must be signed in to change notification settings

apache/couchdb-nano

NPM

Nano

OfficalApache CouchDB library forNode.js.

Features:

  • Minimalistic - There is only a minimum of abstraction between you andCouchDB.
  • Pipes - Proxy requests from CouchDB directly to your end user. (...AsStream functions only)
  • Promises - The vast majority of library calls return native Promises.
  • TypeScript - Detailed TypeScript definitions are built in.
  • Errors - Errors are proxied directly from CouchDB: if you know CouchDByou already knownano.

Installation

  1. Installnpm
  2. npm install nano

or savenano as a dependency of your project with

npm install --save nano

Note the minimum required version of Node.js is 10.

Table of contents

Getting started

To usenano you need to connect it to your CouchDB install, to do that:

constnano=require('nano')('http://localhost:5984');

Note: Supplying authentication credentials in the URL e.g.http://admin:mypassword@localhost:5984 is deprecated. Usenano.auth instead.

To create a new database:

nano.db.create('alice');

and to use an existing database:

constalice=nano.db.use('alice');

Under-the-hood, calls likenano.db.create are making HTTP API calls to the CouchDB service. Such operations areasynchronous. There are two ways to receive the asynchronous data back from the library

  1. Promises
nano.db.create('alice').then((data)=>{// success - response is in 'data'}).catch((err)=>{// failure - error information is in 'err'})

or in the async/await style:

try{constresponse=awaitnano.db.create('alice')// succeededconsole.log(response)}catch(e){// failedconsole.error(e)}
  1. Callbacks
nano.db.create('alice',(err,data)=>{// errors are in 'err' & response is in 'data'})

Innano the callback function receives always three arguments:

  • err - The error, if any.
  • body - The HTTPresponse body from CouchDB, if no error.JSON parsed body, binary for non JSON responses.
  • header - The HTTPresponse header from CouchDB, if no error.

The documentation will follow theasync/await style.


A simple but complete example in theasync/await style:

asyncfunctionasyncCall(){awaitnano.db.destroy('alice')awaitnano.db.create('alice')constalice=nano.use('alice')constresponse=awaitalice.insert({happy:true},'rabbit')returnresponse}asyncCall()

Running this example will produce:

you have inserted a document with an _id of rabbit.{ ok: true,  id: 'rabbit',  rev: '1-6e4cb465d49c0368ac3946506d26335d' }

You can also see your document in futon (http://localhost:5984/_utils).

Configuration

Configuring nano to use your database server is as simple as:

constnano=require('nano')('http://localhost:5984')constdb=nano.use('foo');

If you don't need to instrument database objects you can simply:

// nano parses the URL and knows this is a databaseconstdb=require('nano')('http://localhost:5984/foo');

You can also pass options to the require to specify further configuration options you can pass an object literal instead:

// nano parses the URL and knows this is a databaseconstopts={url:'http://localhost:5984/foo',requestDefaults:{proxy:{protocol:'http',host:'myproxy.net'},headers:{customheader:'MyCustomHeader'}}};constdb=require('nano')(opts);

Nano works perfectly well over HTTPS as long as the SSL cert is signed by a certification authority known by your client operating system. If you have a custom or self-signed certificate, you may need to create your own HTTPS agent and pass it to Nano e.g.

consthttpsAgent=newhttps.Agent({ca:'/path/to/cert',rejectUnauthorized:true,keepAlive:true,maxSockets:6})constnano=Nano({url:process.env.COUCH_URL,requestDefaults:{agent:httpsAgent,}})

Please checkaxios for more information on the defaults. They support features like proxies, timeout etc.

You can tell nano to not parse the URL (maybe the server is behind a proxy, is accessed through a rewrite rule or other):

// nano does not parse the URL and return the server api// "http://localhost:5984/prefix" is the CouchDB server rootconstcouch=require('nano')({url :"http://localhost:5984/prefix"parseUrl :false});constdb=couch.use('foo');

Pool size and open sockets

A very important configuration parameter if you have a high traffic website and are usingnano is the HTTP pool size. By default, the Node.js HTTP global agent has a infinite number of active connections that can run simultaneously. This can be limited to user-defined number (maxSockets) of requests that are "in flight", while others are kept in a queue. Here's an example explicitly using the Node.js HTTP agent configured withcustom options:

consthttp=require('http')constmyagent=newhttp.Agent({keepAlive:true,maxSockets:25})constdb=require('nano')({url:'http://localhost:5984/foo',requestDefaults :{agent :myagent}});

TypeScript

There is a full TypeScript definition included in the thenano package. Your TypeScript editor will show you hints as you write your code with thenano library with your own custom classes:

import*asNanofrom'nano'letn=Nano('http://USERNAME:PASSWORD@localhost:5984')letdb=n.db.use('people')interfaceiPersonextendsNano.MaybeDocument{name:string,dob:string}classPersonimplementsiPerson{_id:string_rev:stringname:stringdob:stringconstructor(name:string,dob:string){this._id=undefinedthis._rev=undefinedthis.name=namethis.dob=dob}processAPIResponse(response:Nano.DocumentInsertResponse){if(response.ok===true){this._id=response.idthis._rev=response.rev}}}letp=newPerson('Bob','2015-02-04')db.insert(p).then((response)=>{p.processAPIResponse(response)console.log(p)})

Database functions

nano.db.create(name, [opts], [callback])

Creates a CouchDB database with the givenname, with optionsopts.

awaitnano.db.create('alice',{n:3})

nano.db.get(name, [callback])

Get information about the databasename:

constinfo=awaitnano.db.get('alice')

nano.db.destroy(name, [callback])

Destroys the databasename:

awaitnano.db.destroy('alice')

nano.db.list([callback])

Lists all the CouchDB databases:

constdblist=awaitnano.db.list()

nano.db.listAsStream()

Lists all the CouchDB databases as a stream:

nano.db.listAsStream().on('error',(e)=>console.error('error',e)).pipe(process.stdout);

nano.db.compact(name, [designname], [callback])

Compactsname, ifdesignname is specified also compacts its views.

nano.db.replicate(source, target, [opts], [callback])

Replicatessource totarget with optionsopts. Thetargetdatabasehas to exist, addcreate_target:true toopts to create it prior toreplication:

constresponse=awaitnano.db.replicate('alice','http://admin:password@otherhost.com:5984/alice',{create_target:true})

nano.db.replication.enable(source, target, [opts], [callback])

Enables replication using the new CouchDB api fromsource totargetwith optionsopts.target has to exist, addcreate_target:true toopts to create it prior to replication. Replication will survive server restarts.

constresponse=awaitnano.db.replication.enable('alice','http://admin:password@otherhost.com:5984/alice',{create_target:true})

nano.db.replication.query(id, [opts], [callback])

Queries the state of replication using the new CouchDB API. Theid comes from the responsegiven by the call toreplication.enable:

constr=awaitnano.db.replication.enable('alice','http://admin:password@otherhost.com:5984/alice',{create_target:true})constq=awaitnano.db.replication.query(r.id)

nano.db.replication.disable(id, [opts], [callback])

Disables replication using the new CouchDB API. Theid comes from the response givenby the call toreplication.enable:

constr=awaitnano.db.replication.enable('alice','http://admin:password@otherhost.com:5984/alice',{create_target:true})awaitnano.db.replication.disable(r.id);

nano.db.changes(name, [params], [callback])

Asks for the changes feed ofname,params contains additionsto the query string.

constc=awaitnano.db.changes('alice')

nano.db.changesAsStream(name, [params])

Same asnano.db.changes but returns a stream.

nano.db.changes('alice').pipe(process.stdout);

nano.db.info([callback])

Gets database information:

constinfo=awaitnano.db.info()

nano.use(name)

Returns a database object that allows you to perform operations against that database:

constalice=nano.use('alice');awaitalice.insert({happy:true},'rabbit')

The database object can be used to access theDocument Functions.

nano.db.use(name)

Alias fornano.use

nano.db.scope(name)

Alias fornano.use

nano.scope(name)

Alias fornano.use

nano.request(opts, [callback])

Makes a custom request to CouchDB. This can be used to create your own HTTP request to the CouchDBserver, to perform operations where there is nonano function that encapsulates it. The availableopts are:

  • opts.db – the database name
  • opts.method – the http method, defaults toget
  • opts.path – the full path of the request, overridesopts.doc andopts.att
  • opts.doc – the document name
  • opts.att – the attachment name
  • opts.qs – query string parameters, appended after any existingopts.path,opts.doc, oropts.att
  • opts.content_type – the content type of the request, default tojson
  • opts.headers – additional http headers, overrides existing ones
  • opts.body – the document or attachment body
  • opts.encoding – the encoding for attachments
  • opts.multipart – array of objects for multipart request
  • opts.stream - iftrue, arequest object is returned. Defaultfalse and a Promise is returned.

nano.relax(opts, [callback])

Alias fornano.request

nano.config

An object containing thenano configurations, possible keys are:

  • url - the CouchDB URL
  • db - the database name

nano.updates([params], [callback])

Listen to db updates, the availableparams are:

  • params.feed – Type of feed. Can be one of
  • longpoll: Closes the connection after the first event.
  • continuous: Send a line of JSON per event. Keeps the socket open until timeout.
  • eventsource: Like, continuous, but sends the events in EventSource format.
  • params.timeout – Number of seconds until CouchDB closes the connection. Default is 60.
  • params.heartbeat – Whether CouchDB will send a newline character (\n) on timeout. Default is true.

nano.info([callback])

Fetch information about the CouchDB cluster:

constinfo=awaitnano.info()

The response is an object withCouchDB cluster information.

Document functions

db.insert(doc, [params], [callback])

Insertsdoc in the database with optionalparams. If params is a string, it's assumed it is the intended document_id. If params is an object, it's passed as query string parameters anddocName is checked for defining the document_id:

constalice=nano.use('alice');constresponse=awaitalice.insert({happy:true},'rabbit')

Theinsert function can also be used with the method signaturedb.insert(doc,[callback]), where thedoc contains the_id field e.g.

constalice=nano.use('alice')constresponse=awaitalice.insert({_id:'myid',happy:true})

and also used to update an existing document, by including the_rev token in the document being saved:

constalice=nano.use('alice')constresponse=awaitalice.insert({_id:'myid',_rev:'1-23202479633c2b380f79507a776743d5',happy:false})

db.destroy(docname, rev, [callback])

Removes a document from CouchDB whose_id isdocname and whose revision (_rev) isrev:

constresponse=awaitalice.destroy('rabbit','3-66c01cdf99e84c83a9b3fe65b88db8c0')

db.get(docname, [params], [callback])

Gets a document from CouchDB whose_id isdocname:

constdoc=awaitalice.get('rabbit')

or with optionalquery stringparams:

constdoc=awaitalice.get('rabbit',{revs_info:true})

If you passattachments=true, thedoc._attachments.attachmentNameN.data fields will contain thebase-64 encoded attachments.Or, you can usedb.multipart.getand parse the returned buffer to get the document and attachments.

See theattachments methods to retrievejust an attachment.

db.head(docname, [callback])

Same asget but lightweight version that returns headers only:

constheaders=awaitalice.head('rabbit')

Note: if you callalice.head in the callback style, the headers are returned to you as the third argument of the callback function.

db.bulk(docs, [params], [callback])

Bulk operations(update/delete/insert) on the database, refer to theCouchDB doc e.g:

constdocuments=[{a:1,b:2},{_id:'tiger',striped:true}];constresponse=awaitalice.bulk({docs:documents})

db.list([params], [callback])

List all the docs in the database .

constdoclist=awaitalice.list().then((body)=>{body.rows.forEach((doc)=>{console.log(doc);})});

or with optional query string additionsparams:

constdoclist=awaitalice.list({include_docs:true})

db.listAsStream([params])

List all the docs in the database as a stream.

alice.listAsStream().on('error',(e)=>console.error('error',e)).pipe(process.stdout)

db.fetch(docnames, [params], [callback])

Bulk fetch of the database documents,docnames are specified as perCouchDB doc.additional query stringparams can be specified,include_docs is always settotrue.

constkeys=['tiger','zebra','donkey'];constdatat=awaitalice.fetch({keys:keys})

db.fetchRevs(docnames, [params], [callback])

** changed in version 6 **

Bulk fetch of the revisions of the database documents,docnames are specified as perCouchDB doc.additional query stringparams can be specified, this is the same method as fetch butinclude_docs is not automatically set totrue.

db.createIndex(indexDef, [callback])

Create index on database fields, as specified inCouchDB doc.

constindexDef={index:{fields:['foo']},name:'fooindex'};constresponse=awaitalice.createIndex(indexDef)

Reading Changes Feed

Nano provides a low-level API for making calls to CouchDB's changes feed, or if you want areliable, resumable changes feed follower, then you need thechangesReader.

There are three ways to start listening to the changes feed:

  1. changesReader.start() - to listen to changes indefinitely by repeated "long poll" requests. This mode continues to poll for changes untilchangesReader.stop() is called, at which point any active long poll will be canceled.
  2. changesReader.get() - to listen to changes until the end of the changes feed is reached, by repeated "long poll" requests. Once a response with zero changes is received, the 'end' event will indicate the end of the changes and polling will stop.
  3. changesReader.spool() - listen to changes in one long HTTP request. (as opposed to repeated round trips) - spool is faster but less reliable.

Note: for.get() &.start(), the sequence of API calls can be paused by callingchangesReader.pause() and resumed by callingchangesReader.resume().

Set up your database connection and then choosechangesReader.start() to listen to that database's changes:

constdb=nano.db.use('mydb')db.changesReader.start().on('change',(change)=>{console.log(change)}).on('batch',(b)=>{console.log('a batch of',b.length,'changes has arrived');}).on('seq',(s)=>{console.log('sequence token',s);}).on('error',(e)=>{console.error('error',e);})

Note: you probably want to monitoreither thechange orbatch event, not both.

If you wantchangesReader to hold off making the next_changes API call until you are ready, then supplywait:true in the options toget/start. The next request will only fire when you callchangesReader.resume():

db.changesReader.get({wait:true}).on('batch',(b)=>{console.log('a batch of',b.length,'changes has arrived');// do some asynchronous work here and call "changesReader.resume()"// when you're ready for the next API call to be dispatched.// In this case, wait 5s before the next changes feed request.setTimeout(()=>{db.changesReader.resume()},5000)}).on('end',()=>{console.log('changes feed monitoring has stopped');});

You may supply a number of options when you start to listen to the changes feed:

ParameterDescriptionDefault valuee.g.
batchSizeThe maximum number of changes to ask CouchDB for per HTTP request. This is the maximum number of changes you will receive in abatch event.100500
sinceThe position in the changes feed to start from where0 means the beginning of time,now means the current position or a string token indicates a fixed position in the changes feednow390768-g1AAAAGveJzLYWBgYMlgTmGQ
includeDocsWhether to include document bodies or notfalsee.g. true
waitForget/start mode, automatically pause the changes reader after each request. When the the user callsresume(), the changes reader will resume.falsee.g. true
fastChangesAdds a seq_interval parameter to fetch changes more quicklyfalsetrue
selectorFilters the changes feed with the supplied Mango selectornull{"name":"fred}
timeoutThe number of milliseconds a changes feed request waits for data6000010000

The events it emits are as follows:s

EventDescriptionData
changeEach detected change is emitted individually. Only available inget/start modes.A change object
batchEach batch of changes is emitted in bulk in quantities up tobatchSize.An array of change objects
seqEach new sequence token (per HTTP request). This token can be passed intoChangesReader as thesince parameter to resume changes feed consumption from a known point. Only available inget/start modes.String
errorOn a fatal error, a descriptive object is returned and change consumption stops.Error object
endEmitted when the end of the changes feed is reached.ChangesReader.get() mode only,Nothing

TheChangesReader library will handle many temporal errors such as network connectivity, service capacity limits and malformed data but it will emit anerror event and exit when fed incorrect authentication credentials or an invalidsince token.

Thechange event delivers a change object that looks like this:

{"seq":"8-g1AAAAYIeJyt1M9NwzAUBnALKiFOdAO4gpRix3X","id":"2451be085772a9e588c26fb668e1cc52","changes":[{"rev":"4-061b768b6c0b6efe1bad425067986587"}],"doc":{"_id":"2451be085772a9e588c26fb668e1cc52","_rev":"4-061b768b6c0b6efe1bad425067986587","a":3}}

N.B

  • doc is only present ifincludeDocs:true is supplied
  • seq is not present for every change

Theid is the unique identifier of the document that changed and thechanges array contains the document revision tokens that were written to the database.

Thebatch event delivers an array of change objects.

Partition Functions

Functions related topartitioned databases.

Create a partitioned database by passing{ partitioned: true } todb.create:

awaitnano.db.create('my-partitioned-db',{partitioned:true})

The database can be used as normal:

constdb=nano.db.use('my-partitioned-db')

but documents must have a two-part_id made up of<partition key>:<document id>. They are insert withdb.insert as normal:

constdoc={_id:'canidae:dog',name:'Dog',latin:'Canis lupus familiaris'}awaitdb.insert(doc)

Documents can be retrieved by their_id usingdb.get:

constdoc=db.get('canidae:dog')

Mango indexes can be created to operate on a per-partition index by supplyingpartitioned: true on creation:

consti={ddoc:'partitioned-query',index:{fields:['name']},name:'name-index',partitioned:true,type:'json'}// instruct CouchDB to create the indexawaitdb.index(i)

Search indexes can be created by writing a design document withopts.partitioned = true:

// the search definitionconstfunc=function(doc){index('name',doc.name)index('latin',doc.latin)}// the design document containing the search definition functionconstddoc={_id:'_design/search-ddoc',indexes:{search-index:{index:func.toString()}},options:{partitioned:true}}awaitdb.insert(ddoc)

MapReduce views can be created by writing a design document withopts.partitioned = true:

constfunc=function(doc){emit(doc.family,doc.weight)}// Design Documentconstddoc={_id:'_design/view-ddoc',views:{family-weight:{map:func.toString(),reduce:'_sum'}},options:{partitioned:true}}// create design documentawaitdb.insert(ddoc)

db.partitionInfo(partitionKey, [callback])

Fetch the stats of a single partition:

conststats=awaitalice.partitionInfo('canidae')

db.partitionedList(partitionKey, [params], [callback])

Fetch documents from a database partition:

// fetch document id/revs from a partitionconstdocs=awaitalice.partitionedList('canidae')// add document bodies but limit size of responseconstdocs=awaitalice.partitionedList('canidae',{include_docs:true,limit:5})

db.partitionedListAsStream(partitionKey, [params])

Fetch documents from a partition as a stream:

// fetch document id/revs from a partitionnano.db.partitionedListAsStream('canidae').on('error',(e)=>console.error('error',e)).pipe(process.stdout)// add document bodies but limit size of responsenano.db.partitionedListAsStream('canidae',{include_docs:true,limit:5}).on('error',(e)=>console.error('error',e)).pipe(process.stdout)

db.partitionedFind(partitionKey, query, [params])

Query documents from a partition by supplying a Mango selector:

// find document whose name is 'wolf' in the 'canidae' partitionawaitdb.partitionedFind('canidae',{'selector' :{'name':'Wolf'}})

db.partitionedFindAsStream(partitionKey, query)

Query documents from a partition by supplying a Mango selector as a stream:

// find document whose name is 'wolf' in the 'canidae' partitiondb.partitionedFindAsStream('canidae',{'selector' :{'name':'Wolf'}}).on('error',(e)=>console.error('error',e)).pipe(process.stdout)

db.partitionedSearch(partitionKey, designName, searchName, params, [callback])

Search documents from a partition by supplying a Lucene query:

constparams={q:'name:\'Wolf\''}awaitdb.partitionedSearch('canidae','search-ddoc','search-index',params)// { total_rows: ... , bookmark: ..., rows: [ ...] }

db.partitionedSearchAsStream(partitionKey, designName, searchName, params)

Search documents from a partition by supplying a Lucene query as a stream:

constparams={q:'name:\'Wolf\''}db.partitionedSearchAsStream('canidae','search-ddoc','search-index',params).on('error',(e)=>console.error('error',e)).pipe(process.stdout)// { total_rows: ... , bookmark: ..., rows: [ ...] }

db.partitionedView(partitionKey, designName, viewName, params, [callback])

Fetch documents from a MapReduce view from a partition:

constparams={startkey:'a',endkey:'b',limit:1}awaitdb.partitionedView('canidae','view-ddoc','view-name',params)// { rows: [ { key: ... , value: [Object] } ]}

db.partitionedViewAsStream(partitionKey, designName, viewName, params)

Fetch documents from a MapReduce view from a partition as a stream:

constparams={startkey:'a',endkey:'b',limit:1}db.partitionedViewAsStream('canidae','view-ddoc','view-name',params).on('error',(e)=>console.error('error',e)).pipe(process.stdout)// { rows: [ { key: ... , value: [Object] } ]}

Multipart functions

db.multipart.insert(doc, attachments, params, [callback])

Inserts adoc together withattachments andparams. If params is a string, it's assumed as the intended document_id. If params is an object, its passed as query string parameters anddocName is checked for defining the_id. Refer to thedoc for more details.Theattachments parameter must be an array of objects withname,data andcontent_type properties.

constfs=require('fs');fs.readFile('rabbit.png',(err,data)=>{if(!err){awaitalice.multipart.insert({foo:'bar'},[{name:'rabbit.png',data:data,content_type:'image/png'}],'mydoc')}});

db.multipart.get(docname, [params], [callback])

Getdocname together with its attachments viamultipart/related request with optionalquery string additions. The multipart response body is aBuffer.

constresponse=awaitalice.multipart.get('rabbit')

Attachments functions

db.attachment.insert(docname, attname, att, contenttype, [params], [callback])

Inserts an attachmentattname todocname, in most casesparams.rev is required. Refer to theCouchDB doc for more details.

constfs=require('fs');fs.readFile('rabbit.png',(err,data)=>{if(!err){awaitalice.attachment.insert('rabbit','rabbit.png',data,'image/png',{rev:'12-150985a725ec88be471921a54ce91452'})}});

db.attachment.insertAsStream(docname, attname, att, contenttype, [params])

As of Nano 9.x, the functiondb.attachment.insertAsStream is now deprecated. Now simply passa readable stream todb.attachment.insert as the third paramseter.

db.attachment.get(docname, attname, [params], [callback])

Getdocname's attachmentattname with optional query string additionsparams.

constfs=require('fs');constbody=awaitalice.attachment.get('rabbit','rabbit.png')fs.writeFile('rabbit.png',body)

db.attachment.getAsStream(docname, attname, [params])

constfs=require('fs');alice.attachment.getAsStream('rabbit','rabbit.png').on('error',e=>console.error).pipe(fs.createWriteStream('rabbit.png'));

db.attachment.destroy(docname, attname, [params], [callback])

changed in version 6

Destroy attachmentattname ofdocname's revisionrev.

constresponse=awaitalice.attachment.destroy('rabbit','rabbit.png',{rev:'1-4701d73a08ce5c2f2983bf7c9ffd3320'})

Views and design functions

db.view(designname, viewname, [params], [callback])

Calls a view of the specifieddesignname with optional query stringparams. If you're looking to filter the view results by key(s) pass an array of keys, e.g{ keys: ['key1', 'key2', 'key_n'] }, asparams.

constbody=awaitalice.view('characters','happy_ones',{key:'Tea Party',include_docs:true})body.rows.forEach((doc)=>{console.log(doc.value)})

or

constbody=awaitalice.view('characters','soldiers',{keys:['Hearts','Clubs']})

Whenparams is not supplied, or no keys are specified, it will simply return all documents in the view:

constbody=awaitalice.view('characters','happy_ones')
constbody=alice.view('characters','happy_ones',{include_docs:true})

db.viewAsStream(designname, viewname, [params])

Same asdb.view but returns a stream:

alice.viewAsStream('characters','happy_ones',{reduce:false}).on('error',(e)=>console.error('error',e)).pipe(process.stdout);

db.viewWithList(designname, viewname, listname, [params], [callback])

Calls a list function fed by the given view from the specified design document.

constbody=awaitalice.viewWithList('characters','happy_ones','my_list')

db.viewWithListAsStream(designname, viewname, listname, [params], [callback])

Calls a list function fed by the given view from the specified design document as a stream.

alice.viewWithListAsStream('characters','happy_ones','my_list').on('error',(e)=>console.error('error',e)).pipe(process.stdout);

db.show(designname, showname, doc_id, [params], [callback])

Calls a show function from the specified design for the document specified by doc_id withoptional query string additionsparams.

constdoc=awaitalice.show('characters','format_doc','3621898430')

Take a look at theCouchDB wikifor possible query paramaters and more information on show functions.

db.atomic(designname, updatename, docname, [body], [callback])

Calls the design's update function with the specified doc in input.

constresponse=awaitdb.atomic('update','inplace','foobar',{field:'foo',value:'bar'})

Note that the data is sent in the body of the request.An example update handler follows:

"updates":{"in-place" : "function(doc, req) {varrequest_body=JSON.parse(req.body)varfield=request_body.fieldvarvalue=request_body.valuevarmessage='set '+field+' to '+valuedoc[field]=valuereturn[doc,message]}"}

db.search(designname, searchname, params, [callback])

Calls a view of the specified design with optional query string additionsparams.

constresponse=awaitalice.search('characters','happy_ones',{q:'cat'})

or

constdrilldown=[['author','Dickens']['publisher','Penguin']]constresponse=awaitalice.search('inventory','books',{q:'*:*',drilldown:drilldown})

Check out the tests for a fully functioning example.

db.searchAsStream(designname, searchname, params)

Calls a view of the specified design with optional query string additionsparams. Returns stream.

alice.search('characters','happy_ones',{q:'cat'}).pipe(process.stdout);

db.find(selector, [callback])

Perform a"Mango" query by supplying a JavaScript object containing a selector:

// find documents where the name = "Brian" and age > 25.constq={selector:{name:{"$eq":"Brian"},age :{"$gt":25}},fields:["name","age","tags","url"],limit:50};constresponse=awaitalice.find(q)

db.findAsStream(selector)

Perform a"Mango" query by supplying a JavaScript object containing a selector, but return a stream:

// find documents where the name = "Brian" and age > 25.constq={selector:{name:{"$eq":"Brian"},age :{"$gt":25}},fields:["name","age","tags","url"],limit:50};alice.findAsStream(q).on('error',(e)=>console.error('error',e)).pipe(process.stdout);

using cookie authentication

Nano supports making requests using CouchDB'scookie authentication functionality. If you initialiseNano so that it is cookie-aware, you may callnano.auth first to get a session cookie. Nano will behave like a web browser, remembering your session cookie and refreshing it if a new one is received in a future HTTP response.

constnano=require('nano')({url:'http://localhost:5984',requestDefaults:{jar:true}})constusername='user'constuserpass='pass'constdb=nano.db.use('mydb')// authenticateawaitnano.auth(username,userpass)// requests from now on are authenticatedconstdoc=awaitdb.get('mydoc')console.log(doc)

The second request works because thenano library has remembered theAuthSession cookie that was invisibily returned by thenano.auth call.

When you have a session, you can see what permissions you have by calling thenano.session function

constdoc=awaitnano.session()// { userCtx: { roles: [ '_admin', '_reader', '_writer' ], name: 'rita' },  ok: true}

Advanced features

Getting uuids

If your application needs to generate UUIDs, then CouchDB can provide some for you

constresponse=awaitnano.uuids(3)// { uuids: [// '5d1b3ef2bc7eea51f660c091e3dffa23',// '5d1b3ef2bc7eea51f660c091e3e006ff',// '5d1b3ef2bc7eea51f660c091e3e007f0',//]}

The first parameter is the number of uuids to generate. If omitted, it defaults to 1.

Extending nano

nano is minimalistic but you can add your own features withnano.request(opts)

For example, to create a function to retrieve a specific revision of therabbit document:

functiongetrabbitrev(rev){returnnano.request({db:'alice',doc:'rabbit',method:'get',params:{rev:rev}});}getrabbitrev('4-2e6cdc4c7e26b745c2881a24e0eeece2').then((body)=>{console.log(body);});

Pipes

You can pipe the return values of certain nano functions like other stream. For example if ourrabbit document has an attachment with namepicture.png you can pipe it to awritable stream:

constfs=require('fs');constnano=require('nano')('http://127.0.0.1:5984/');constalice=nano.use('alice');alice.attachment.getAsStream('rabbit','picture.png').on('error',(e)=>console.error('error',e)).pipe(fs.createWriteStream('/tmp/rabbit.png'));

then open/tmp/rabbit.png and you will see the rabbit picture.

Functions that return streams instead of a Promise are:

  • nano.db.listAsStream

attachment functions:

  • db.attachment.getAsStream
  • db.attachment.insertAsStream

and document level functions

  • db.listAsStream

Logging

When instantiating Nano, you may supply the function that will perform the logging of requests and responses. In its simplest for, simply passconsole.log as your logger:

constnano=Nano({url:process.env.COUCH_URL,log:console.log})// all requests and responses will be sent to console.log

You may supply your own logging function to format the data before output:

consturl=require('url')constlogger=(data)=>{// only output logging if there is an environment variable setif(process.env.LOG==='nano'){// if this is a requestif(typeofdata.err==='undefined'){constu=newurl.URL(data.uri)console.log(data.method,u.pathname,data.qs)}else{// this is a responseconstprefix=data.err ?'ERR' :'OK'console.log(prefix,data.headers.statusCode,JSON.stringify(data.body).length)}}}constnano=Nano({url:process.env.COUCH_URL,log:logger})// all requests and responses will be formatted by my code// GET /cities/_all_docs { limit: 5 }// OK 200 468

Tutorials, examples in the wild & screencasts

Roadmap

Checkissues

Tests

To run (and configure) the test suite simply:

cd nanonpm installnpm runtest

Meta

https://freenode.org/

Release

To create a new release of nano. Run the following commands on the main branch

  npm version {patch|minor|major}  github push  origin main --tags  npm publish

[8]ページ先頭

©2009-2025 Movatter.jp