Pagination for search indexes on cloudant - node.js

I have a cloudant db which contains documents for access logs of users. Example:
{
"name": "John Doe",
"url": "somepage.html",
"dateaccessed": "2016-08-23T21:20:25.502Z"
}
I created a search index with a function:
function (doc) {
if(doc.dateaccessed) {
var d = new Date(doc.dateaccessed);
index("dateaccessed", d.getTime(), {store: true});
}
}
Now this setup is working as expected with just a normal query. Example
{
q: 'dateaccessed:[1420041600000 TO 1471987625266]',
include_docs: true,
sort: '-dateaccessed<number>',
}
However, I wish to limit the results - let's say 5 at a time (which can be done with the "limit: 5" argument), and I want to somehow make a pagination - be able to move to the next 5 results or the previous 5 results.
I checked the cloudant documentation and there's an argument there called "bookmark" (https://cloudant.com/for-developers/search/) but I'm not sure how to use it.
May I request for any insights on this?

The Cloudant documentation shows examples on how to use bookmarks, but the gist is that you get a bookmark from the server in your search response, when requesting the next page, you use the bookmark received in your request with the bookmark parameter in either your JSON object for POST, or in the query params for GET.

Related

Hubspot API - list of properties needed (nodejs)

I am integrating the hubspot API to track user interaction with our site. I am creating dynamic lists and I want to filter a user into a certain contact list by which URL they visit.
"filters": [
[
{
"operator": "CONTAINS",
"property": "hs_URL",
"value": `${id}`
},
],
]
I keep getting this error for all my attempts:
{"status":"error","message":"Couldn't find a Property with the given name 'hs_URL'","correlationId":"0723dcee-534b-4f92-9104-509d6885abbe","propertiesErrorCode":"PROPERTY_NOT_FOUND"},
I cannot seem to find a master property list and have tried many string combinations. Anyone familiar with hubspot property lists would be my savior.
Thank you~!
It's been a few months, so you may not need this anymore, but since I landed here while looking for a way to get all the properties from an object type in hubspot using nodejs, this might help others looking for the solution.
The master list of properties can be retrieved with the following API call:
const response = await hubspotClient.crm.properties.coreApi.getAll(objectType, false);
The arguments for getAll() expect:
objectType: a string, i.e "contacts".
archived: a boolean, i.e false. Set this true if you want to get archived properties.
The following code was adapted based on this page from the hubspot API docs:
https://developers.hubspot.com/docs/api/crm/properties
Once you're on the page, you can click on the "Endpoints" Tab to reveal code snippets for multiple environments, including nodejs.
For this example, getProperties(), retrieves all properties for a given object type. I used contacts for the object type, which I believe is where you are storing the url property, but you could use the same function to get properties for other object types such as companies or deals.
It might be worth noting that I mapped the results to return just the property names, which sounds like all you need for your case, but more information is contained in the results if you need it. Just remove this bit to get more information on each property:
.map(prop => prop.name)
const hubspot = require('#hubspot/api-client')
const hubspotClient = new hubspot.Client({ apiKey: "YOUR_API_KEY" })
const getProperties = async (objectType) => {
try {
const response = await hubspotClient.crm.properties.coreApi.getAll(objectType, false);
return response.body.results.map(prop => prop.name);
} catch (e) {
e.message === 'HTTP request failed'
? console.error(JSON.stringify(e.response, null, 2))
: console.error(e);
}
}
Here's an example for running the function to get a list of all property names for contacts.
(async () => {
var properties = await getProperties("contacts");
console.log(JSON.stringify(properties ,null,2));
})();
It took me a bit to find this, so figured I would post here in the hopes it saves time for someone else. This is the first time I've posted a solution, and I'm pretty new to this API and Hubspot in general, so feedback and/or better solutions are welcome. Cheers.

NetSuite SuiteScript 2.0 How to specify field, sublist field or subrecord field in N/search create API

I have a button on the Purchase Order record that performs a saved search query on the current record and then uses the http module to send that data via a POST to a url. That url then sends the data posted back as part of the success confirmation. The idea with the saved search is to create a javascript object that contains all the data that I want from the purchase order (main record and items sublist with subrecords) and then to use JSON.stringify to create a JSON payload for the http POST. I can't do this with the currentRecord because if you inspect it it only contains the internal id. This would also prevent me from having to go to the great lengths of writing a lot of code to manually build up a JSON string from the currentRecord.
Unfortunately I don't really understand how to specify the column names in the dynamically created saved search. Sometimes it looks to me like the column names are those from the NetSuite Records Browser and other times the script gives an error (column not found) if I use a column name from the NetSuite Records Browser (for example currencysymbol).
I'm also not sure how to specify columns that appear in sublists or subrecords in sublists. I tried to use item.itemtype but this gave me a column not found error. Just item completes successfully but I'm not sure whether this was really successfull since it is difficult to decode the returned result after the JSON.stringify (it adds a lot of backslashes). Using console.log (for some reason I don't get anything back using the NetSuite log.audit) is also quite difficult, although it looks like it is returning an array with 5 rows. So using item might sort of be successful. I say sort of because I have 3 item lines and it is returning 5 array rows.
So basically I would like to know where one can find the names of the columns to use in NetSuite for a saved search; and also how to specify sublist column names and sublist subrecord column names in a saved search.
/**
* #NApiVersion 2.0
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/ui/dialog', 'N/currentRecord', 'N/record', 'N/url', 'N/http', 'N/search'], function (dialog, rec, record, url, http, s) {
function pageInit(context) {
// All client scripts need at least one dummy function.
} // pageInit
function onButtonClick() {
var currentRecord = rec.get();
// Create a saved search dynamically.
var rs = s.create({
type: s.Type.PURCHASE_ORDER,
filters: [
["mainline", s.Operator.IS, "F"], "and",
["internalid", s.Operator.IS, currentRecord.id]
],
columns: [
"internalid",
"currency",
{
name: "item",
sort: s.Sort.ASC // DESC
}
]
});
var myPostDataObj = rs.run().getRange(0, 1000);
console.log(myPostDataObj);
var headers = {
'Content-Type': 'application/json; charset=utf-8',
};
http.post.promise({
url: 'http://httpbin.org:80/post',
body: JSON.stringify(myPostDataObj),
headers: headers
})
.then(function(response){
console.log('SUCCESS: ' + JSON.stringify(response));
})
.catch(function onRejected(reason) {
console.log('ERROR: ' + JSON.stringify(reason));
})
}
return {
pageInit: pageInit,
onButtonClick: onButtonClick
};
}); // Define
There are two Chrome extensions I suggest you get;
NetSuite Field Explorer. This extension will show you the ids (and values) of all the fields in a NetSuite record.
NetSuite Search Export. This extension will convert/export a saved search to SuiteScript.
For what you're doing, I would create your saved search in the UI, and then export it using the Saved Search Export extension, paste that into your code (where s.create is), and work from there.
The first extension is nice to get to the sublist field ids. Saves a lookup in the record browser.

CouchDB View not returning documents when ?key specified

I'm coming to CouchDB from an SQL background and am trying to do the common "SELECT FROM DB where field = someValue". I've created the following design document:
{
"_id": "_design/views",
"views": {
"byRubric": {
"map": "function(doc) {if(doc.idRubric){emit(doc._id, doc.idRubric);} }"
}
}
}
If I query the CouchDB table using the following URL, it correctly returns all 15 documents in the table:
http://localhost:5984/rubric_content/_design/views/_view/byRubric
If, however, I try to get those documents in this view which have a particular value in the idRubric field, one which I know is present by, for example, executing the following url, I get 0 documents back when, in fact, 12 of the 15 documents have this specific value in the idRubric field. http://localhost:5984/rubric_content/_design/views/_view/byRubric?key="9bf94452c27908f241ab559d2a0d46c5" (no, it doesn't make any difference if the " marks are replaced by %22). The URL does fail if I leave the quote marks off.
What am I missing? Running this locally for test on OSX 10.12.3 using couchdb - Apache CouchDB 1.6.1
Your view is emitting the document with the document with the id as the key.
Instead, you want to emit the the rubricID as the key.
{
"_id": "_design/views",
"views": {
"byRubric": {
"map": "function(doc) {if(doc.idRubric){emit(doc.idRubric);} }"
}
}
}
Then, the query will be the following :
http://localhost:5984/rubric_content/_design/views/_view/byRubric?key="rubric3"
When you use a map, you need to think as if it was a dictionnary. You have a key and a value. You will search for a matching key and get the value.
If you don't emit any value, you can simply use the ?include_docs=true parameter to get the entire document.

Insert multiple records and/or update specific fields and return only new records inserted (MongoDB)

Hi I have a collection as follows
var articles = [
{
"title": "Article title1",
"content": "Article ... content......... 1. ",
"url": "http://matt.wordpress.com/article/X",
"last_fetched_time": new Date();
},
{
"title": "Article title2",
"content": "Article ... content......... 2. ",
"url": "http://matt.blogger.com/article/Y",
"last_fetched_time": new Date();
}
];
db.collection('articles').insert(articles, {safe:true}, function(err, result) {}); //articles collection created
I want to fetch blog feeds from multiple endpoints in parallel periodically and add new articles into the collection and update the last fetched date-time field of the existing articles in the collection. If I'm not asking too much I also want the upsert's callback returns only the new articles inserted.
//fetch articles periodically
fetchArticles = function(req, res) {
async.parallel([
//fetch word press endpoint
//get "title", "content", "url"
//set last_fetched_time with new Date();
//fetch blogger endpoint
//get "title", "content", "url"
//set last_fetched_time with new Date();
],
function(err, results) {
//merge results[0] and results[1] in a batch =[]
//if the article url is not already in the collection, insert article into the articles collection
//if the article url is found in the collection, update article because last_fetched_time changed
//finally return only new inserted articles, not updated ones
db.collection('articles').update(batch, {safe:true, upsert : true}, function(err, result) {
//result = only new articles inserted
});
});
}
url field should be unique and I did
db.articles.ensureIndex({"url":1}, {unique: true, sparse:true, dropDups: true});
The problem is this code doesn't insert new articles
You seem to have your functions mixed around even though I clearly see what you are trying to do.
Your batch you are passing in contains an array of documents that you want to insert/update. The problem is that this functionality is only available to the insert method.
Since you are using the update method, the option to pass in an array of documents for batch processing is not available. Updates with upsert set as you have done are intended to be issued with the primary arguments of a selector and a single 'document'. The idea being that where the selector matches an existing document, that document is updated with the details in document. In the event the match is not found, then a new document is then inserted.
Additionally as you have not used, there is the multi option that can be applied. It's purpose is that when the selector matches more than one document, then the changes are applied to all of the matching documents. Unspecified the behavior is considered to be false and only the first matching document found will be updated.
It would seem that though you wish to have this accompanied by a batch processing functionality, it does not presently exist. There is a JIRA you can follow / support for this.
https://jira.mongodb.org/browse/SERVER-2172
Refer to the links for the functions in the documentation, which explains all the available arguments and options. Also see the shell documentation for a detailed explaination of the options:
http://docs.mongodb.org/manual/reference/method/db.collection.update/

Get a single value from document

Is there a possibility in CouchDB to retrieve a single value from a document? For example, I have a document with 10000 keys like this:
{
"_id": "8098091cc795acde43cd45335373cc92",
"_rev": "2-6d2e0ac43618388cc958b91e5015bba5",
"1":"some value",
"2":"another value",
...
"10000":"last value"
}
and I don't want to parse the whole document each time but just want to get a value of key "2". Is this possible?
EDIT:
Of course, before asking this question I looked through the docs and googled around this but haven't found such possibility. But I'm wondering why this is not possible? In my understanding it is not too much difference between view and document since both of them are sets of key-value pairs, but it is possible to get single value from view using ?key=... in the query string and not possible to do the same for document. Why?
You can use a CouchDB show function to process a document on the server and send arbitrary data to the client. Show functions can do simple things like extracting a single value from the document; or they can convert to a completely different content-type such as XML.
For example:
In database db
which has design document _design/example with show function one_field
you want to fetch document with ID doc_id
but only retrieve the field some_field which has a value "I am the some_field value!"
That query would be:
GET /db/_design/example/_show/one_field/doc_id?name=some_field
The show function would look like this:
function(doc, req) {
// _show function to extract one field
var field_name = req.query.name; // Set to e.g. "some_field"
var field_value = doc[field_name];
return { "code": 200 // HTTP status code
, "headers": // Response headers
{ "content-type": "text/plain" }
, body: field_value
};
}
The design document would look like this:
{ "_id": "_design/example"
, "shows":
{ "one_field": ... } // Paste the above function as a string.
}
CouchDB will return
HTTP 200 OK
Content-Type: text/plain
Content-Length: 26
I am the some_field value!
No. CouchDB is a document oriented DB, so it doesn't support more granular access to the data beyond the overall document itself.
It gives you fine grained indexing, but not actual access.

Resources