smartsheet api exact match during searching - smartsheet-api

i have a node.js script that uses the smartsheet library function. Search works except it is not returning an exact match instead even if the search string has a few characters that match the smartsheet, all those rows are returned. How can you do a search with exact match ?
var options = {
sheetId: xxxxxxxxxxx,
queryParameters: {
query: <string to search>
}
};
// Search sheet.
smartsheet.search.searchSheet(options)
.then(function (data) {
console.log(data);
}
so if i search with 'test' as the search string its returning results where 1 or more characters with in 'test' like 'tes' is a match, it returns those rows..

By default, Smartsheet accepts partial matches - both in the UI as well as via the API.
To restrict to an exact match, enclose the search term in double quotes (").
Using the REST API, you can try: https://api.smartsheet.com/2.0/search/sheets/xxxxxxxxx?query=%22test%22
Or in node:
var options = {
sheetId: xxxxxxxxxxxx,
queryParameters: {
query: '"test"'
}
};
// Search sheet.
smartsheet.search.searchSheet(options)
.then(function (data) {
console.log(data);
});
This is mentioned in the article https://help.smartsheet.com/articles/522231-searching-in-smartsheet#items

Related

Mongoose - populate return _id only instead of a Object [duplicate]

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as
Person.find({})
.populate('books movie', 'title pages director')
.exec()
However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:
Person.find({})
.populate('books', 'title pages')
.populate('movie', 'director')
.exec()
which gives me the expected result and queries.
But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.
After looking into the sourcecode of mongoose, I solved this with:
var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];
Person.find({})
.populate(populateQuery)
.execPopulate()
you can also do something like below:
{path:'user',select:['key1','key2']}
You achieve that by simply passing object or array of objects to populate() method.
const query = [
{
path:'books',
select:'title pages'
},
{
path:'movie',
select:'director'
}
];
const result = await Person.find().populate(query).lean();
Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!
This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html
Let's say you have a BookCollection schema which contains users and books
In order to perform a query and get all the BookCollections with its related users and books you would do this
models.BookCollection
.find({})
.populate('user')
.populate('books')
.lean()
.exec(function (err, bookcollection) {
if (err) return console.error(err);
try {
mongoose.connection.close();
res.render('viewbookcollection', { content: bookcollection});
} catch (e) {
console.log("errror getting bookcollection"+e);
}
//Your Schema must include path
let createdData =Person.create(dataYouWant)
await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

Compare two fields in Waterline/Sails.js query

I want to compare two fields in my Waterline query in Sails.js application, e.g.: SELECT * FROM entity E WHERE E.current < E.max.
I've tried the following code, but it's expecting integer value to be passed to it instead of column name:
Entity.find({
where: {
current: {'<': 'max'}
}
});
So, how do I compare two columns?
I have ran some tests and at the same time read the Waterline documentation. There is no indication of anything that could possibly do comparison of two fields/columns via .find() or .where() methods. Reference: http://sailsjs.org/documentation/concepts/models-and-orm/query-language
Instead, I have used .query() method to compare two fields via SQL string such as :
Entity.query("SELECT * FROM `Entity` E WHERE E.current < E.max", function( err, res) {
if(err) {
//exception
} else {
console.log('response',res);
}
});
The other way would be to use one query to get the max before putting it in the criteria.
EntityOne.find({
sort: 'column DESC'
}).limit(1)
.exec(function(err,found){
var max = found[0]
EntityTwo.find({
where: {
current: {'<': found}
}
}).exec((err,found) {
// Do stuff here
});
});
The query method is ultimately going to be faster however

How to properly instantiate a Waterline Model Object from a sails-mongo native result?

I am using SailsJS on a project and I need to use native() for certain querys. The problem I have is that I can't find a proper way to instantiate a Waterline Model Object from the mongo collection find result. I have being searching information about this and the only thing I have found is the following:
var instance = new Model._model(mongo_result_item);
This should work properly, but when I do instance.save(function(err, ins){}); the model throws an error because of the "_id" field, that should be "id".
I have took a look into sails-mongo code and I found that for the "find" method they do this:
// Run Normal Query on collection
collection.find(where, query.select, queryOptions).toArray(function(err, docs) {
if(err) return cb(err);
cb(null, utils.normalizeResults(docs, self.schema));
});
So the normalizeResults does the magic with the "_id" attribute, and other stuff.
The way I am doing this right now is to require the sails-mongo utils.js file to have access to this method.
Full sample:
var mongoUtils = require('sails-mongo/lib/utils.js');
SampleModel.native(function(nativeErr, collection){
collection.find({ 'field' : value }).toArray(function(collectionErr, results){
if (!results || results.length == 0) return res.restfullInvalidFieldValue({ msg : 'INVALID_VALUE' });
var norm_results = mongoUtils.normalizeResults(results);
var instance = new SampleModel._model(norm_results[0]);
});
});
Is there a better / proper way to achieve this ?
I need to do a native search because I have found a problem with Waterline find() method using strings, where the search should be case sensitive. Every string field on the model is being used as a regular expression match of the form : /^{string}$/i
Searching by a regular expression with the case insensitive flag will give me problems. In the other hand, doing { field : { $regex : new RegExp('^'+regexp_escaped_string+'$') } } could be possible, but I think it will perform worst than { field : value }.
If someone have found a different workaround for the case insensitive problem, please, point me in the right direction.
Thanks in advance.
$regex might help you to search case insensitive string using option paramteter as "i", you can also specify custom regex instead for more information see $regex mongodb documentation.
/**
* PetController
*
* #description :: Server-side logic for managing pets
* #help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
searchByName: function (req,res) {
Pet
.native(function(err, collection) {
if (err) return res.serverError(err);
collection.find(
{
name: { $regex: /like-my-name/, $options: "i" } // here option "i" defines case insensitive
},
{
name: true
})
.toArray(function (err, results) {
if (err) return res.serverError(err);
return res.ok(results);
});
});
}
};
See here for more on native mongo query - https://stackoverflow.com/a/54830760/1828637

Mongodb - How to find string in multiple fields?

Using Pymongo for this scenario.
I have User that has email, first_name, last_name.
I am using this Pymongo snippet:
user_found = users.find({'$or':[
{'email':{'$regex':searchString, '$options':'i'}},
{'first_name':{'$regex':searchString, '$options':'i'}},
{'last_name':{'$regex':searchString, '$options':'i'}}]})
this example works, if I want to find searchString in:
email, or
first_name, or
last_name
now I need to also find searchString in first_name + last_name combined.
how can I do that?
Is there a way in mongo, through the query, to combine the two into a "fullname" then search the fullname?
Easiest way is to add an array field and populate it with all of the variants that you want to search on. Index that array field.
That way you only need one index and your search across all fields is simple and doesn't change when you want to search on some new search variant. You can also normalize the text you put into the search array, for example, lower casing it, removing punctuation etc.
See https://stackoverflow.com/q/8206188/224370
Edit: MongoDB's documentation now covers keyword search and the new full-text search feature.
I had the same problem. I already used regex string search, so my solution was:
generate a helper collection. Here I combine all relevant string, like:
{
search_field: email + " " + first_name + " " + last_name,
ref_id: (id to real object)
}
I then use a regexp to creat what i allow to be looked for:
// logic found here: http://stackoverflow.com/questions/10870372/regex-match-if-string-contain-all-the-words-or-a-condition
var words = query.split(/[ ,]+/);
var regstr = "";
for (var i = 0; i < words.length; ++i) {
var word = words[i];
regstr += "(?=.*?\\b" + word + ")";
}
regstr += "^.*$";
regex = new RegExp(regstr, "i");
This then also gives some flexibility about the order.
Searching is not the fastest, since it still uses regex on all elements, but it is ok for me. (I also index the collection on search_field.
Getting results also becomes a nested call, since first you need to get the _ids you really want, and then you can query for them like so:
connection.find({ "search_field" : regex }, { _id: 0, ref_id: 1 }, { limit: limit, skip: start }).toArray(function (err, docs) {
if (err) throw err;
// map array of documents into simple array of ids
var ids = [];
for (var i = 0; i < docs.length; ++i)
{
var doc = docs[i];
ids.push(doc.ref_id);
}
if (ids.length > 0)
MongooseEmails.find({ "_id": { $in: ids } }, function (err, docres) {
if (err) throw err;
res.send(JSON.stringify(docsres));
});
else
res.send("");
});
This is edited code.. perhaps there is a syntax error, generally, it is working for me.

Looking for help with reading from MongoDB in Node.JS

I have a number of records stored in a MongoDB I'm trying to output them to the browser window by way of a Node.JS http server. I think I'm a good portion of the way along but I'm missing a few little things that are keeping it from actually working.
The code below uses node-mongo-native to connect to the database.
If there is anyone around who can help me make those last few connections with working in node I'd really appreciate it. To be fair, I'm sure this is just the start.
var sys = require("sys");
var test = require("assert");
var http = require('http');
var Db = require('../lib/mongodb').Db,
Connection = require('../lib/mongodb').Connection,
Server = require('../lib/mongodb').Server,
//BSON = require('../lib/mongodb').BSONPure;
BSON = require('../lib/mongodb').BSONNative;
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT;
sys.puts("Connecting to " + host + ":" + port);
function PutItem(err, item){
var result = "";
if(item != null) {
for (key in item) {
result += key + '=' + item[key];
}
}
// sys.puts(sys.inspect(item)) // debug output
return result;
}
function ReadTest(){
var db = new Db('mydb', new Server(host, port, {}), {native_parser:true});
var result = "";
db.open(function (err, db) {
db.collection('test', function(err, collection) {
collection.find(function (err, cursor){
cursor.each( function (err, item) {
result += PutItem(err, item);
});
});
});
});
return result;
}
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("foo"+ReadTest());
}).listen(8124);
console.log('Server running on 8124');
Sources:
- mongo connectivity code:
https://github.com/christkv/node-mongodb-native/blob/master/examples/simple.js
- node. http code: nodejs.org
EDIT CORRECTED CODE
Thanks to Mic below who got me rolling in the right direction. For anyone interested, the corrected solution is here:
function ReadTest(res){
var db = new Db('mydb', new Server(host, port, {}), {native_parser:true});
var result = "";
res.write("in readtest\n");
db.open(function (err, db) {
res.write("now open\n");
db.collection('test', function(err, collection) {
res.write("in collection\n");
collection.find(function (err, cursor){
res.write("found\n");
cursor.each( function (err, item) {
res.write("now open\n");
var x = PutItem(err, item);
sys.puts(x);
res.write(x);
if (item == null) {
res.end('foo');
}
});
});
});
});
}
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write("start\n");
ReadTest(res);
}).listen(8124);
console.log('Server running on 8124');
My guess is that you are returning result, writing the response, and closing the connection before anything is fetched from the db.
One solution would be to pass the response object to where you actually need it, something like:
function readTest(res) {
db.open(function (err, db) {
db.collection('test', function(err, collection) {
collection.find(function (err, cursor) {
res.writeHead(200, {'Content-type' : 'text/plain'});
cursor.each( function (err, item) { res.write(item); });
res.end();
...
Of course, you should also handle errors and try to avoid nesting too many levels, but that's a different discussion.
Instead of writing all the low-level Mongodb access code, you might want to try a simple library like mongous so that you can focus on your data, not on MongoDB quirks.
You might want to try mongoskin too.
Reading documents
To apply specific value filters, we can pass specific values to the find() command. Here is a SQL query:
SELECT * FROM Table1 WHERE name = 'ABC'
which is equivalent to the following in MongoDB (notice Collection1 for Table1):
db.Collection1.find({name: 'ABC'})
We can chain count() to get the number of results, pretty() to get a readable result. The results can be further narrowed by adding additional parameters:
db.Collection1.find({name: 'ABC', rollNo: 5})
It's important to notice that these filters are ANDed together, by default. To apply an OR filter, we need to use $or. These filters will be specified depending upon the structure of the document. Ex: for object attribute name for an object school, we need to specify filter like "school.name" = 'AUHS'
We're using here the DOT notation, by trying to access a nested field name of a field school. Also notice that the filters are quoted, without which we'll get syntax errors.
Equality matches on arrays can be performed:
on the entire arrays
based on any element
based on a specific element
more complex matches using operators
In the below query:
db.Collection1.find({name: ['ABC','XYZ']})
MongoDB is going to identify documents by an exact match to an array of one or more values. Now for these types of queries, the order of elements matters, meaning that we will only match documents that have ABC followed by XYZ and those are the only 2 elements of the array name
{name:["ABC","GHI","XYZ"]},
{name:["DEF","ABC","XYZ"]}
In the above document, let's say that we need to get all the documnts where ABC is the first element. So, we'll use the below filter:
db.Schools.find({'name.0': 'ABC' })