Lucene does not permit use of a * or ? symbol as the first character of a search when going through the query parser. Although lucene permits the use of wildcards at the start for other implementations such as lucene.net, this query parser quirk also flows into Cloudant's Lucene-based search.
Lets say we want to emulate: q=foo:*
Can this be specified as: q=foo:([\u0000 TO \uffff] OR [-Infinity TO Infinity])
and the negation as
q=*:* AND NOT foo:([\u0000 TO \uffff] OR [-Infinity TO Infinity])
One solution is to add an index which names the included field names. For example:
function(doc) {
var included = [];
if(doc.foo) {
index("foo", doc.foo);
included.push("foo");
}
if(doc.bar) {
index("bar", doc.bar);
included.push("bar");
}
if(included.length > 0) {
index("has", included.join(" "));
}
}
You could then use
?q=has:foo
to find all docs with a foo field.
Related
If I have a string like "2020-12-15T12:10:00.202" how can I parse this into NodaTime.LocalDateTime directly, rather than doing something like:
LocalDateTime.FromDateTime(DateTime.Parse("2020-12-15T12:10:00.202"))
And similarly for the other NodaTime types like LocalDate, Instant etc.
You use a LocalDateTimePattern. For example:
// Note: patterns are thread-safe and immutable. Various patterns are provided as
// static properties on the relevant pattern class. If you can't use one of those
// patterns, it's often useful to store the pattern in a static readonly field.
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss.fff");
// There's no Parse/TryParse separation - there's just Parse, which returns a
// ParseResult<T> that indicates success/failure.
ParseResult<LocalDateTime> parsed = pattern.Parse("2020-12-15T12:10:00.202");
// Note: if you're okay with invalid input causing an exception, just use
// parsed.Value directly - it will throw a descriptive exception if parsing failed.
if (parsed.Success)
{
LocalDateTime result = parsed.Value;
// Use the result here
}
else
{
// Handle the failure
}
For more details about text handling, see the section in the user guide.
Note that there's no direct equivalent of DateTime.Parse itself, that tries multiple different date/time formats automatically - but you can use a CompositePatternBuilder<T> to try multiple patterns when parsing if you want.
I am trying to execute a simple query with pattern matching using LIKE in the WHERE clause using node-oracledb NodeJS library, however I can't seem to figure out how to do it. This doesn't seem to work
const baseQuery =
`select item, item_desc
from item_master
where item_level=tran_level
and item like '%:item%'`;
const binds = { item: '550' };
const result = await conn.execute(baseQuery, binds, {});
It keeps throwing the error below-
[Error: ORA-01036: illegal variable name/number] {
errorNum: 1036,
offset: 0
}
I've read the node-oracledb documentation but this seemingly simple use case of pattern match queries doesn't seem to be documented anywhere. Is pattern matching supported? if yes, then what am I doing wrong?
This was answered in your cross post at https://github.com/oracle/node-oracledb/issues/1195
Use a normal bind variable in the SQL statement (which is important for scalability and security, so that data is never treated as part of the SQL statement). Then concatenate whatever pattern matching syntax you want to the data.
To quote sla100's answer in the GitHub issue:
SQL:
and item like :item
JS:
const binds = { item: '%550%' };
You can do this with LIKE comparisons and also REGEXP_LIKE. The node-oracledb documentation also has examples of doing this in WHERE IN.
I'm using GitHub API v 4 to learn GraphQL. Here is a broken query to fetch blobs (files) and their text content for a given branch:
query GetTree($branch: String = "master") {
repository(name: "blog-content", owner: "lzrski") {
branch: ref(qualifiedName: "refs/heads/${branch}") {
name
target {
... on Commit {
tree {
entries {
name
object {
... on Blob {
isBinary
text
}
}
}
}
}
}
}
}
}
As you see on line 3 there is my attempt of guessing interpolation syntax, but it does not work - I leave it as an illustration of my intention.
I could provide a fully qualified name for a revision, but that doesn't seem particularly elegant. Is there any GraphQL native way of manipulating strings?
I don't think there's anything in the GraphQL specification that specifically outlines any methods for manipulating string values within a query.
However, when utilizing GraphQL queries within an actual application, you will provide most of the arguments for your query by utilizing variables that are passed alongside your query inside your request. So rather than being done inside your query, most of your string manipulation will be done within your client code when composing the JSON that will represent your variables.
I'm having problems sending parameters with the ArangoJS library and was wondering if anyone could help.
With the example below, it is possible to execute db.query if parameter values are in the query, but as soon as I try to use bindVars I get silent errors and I can't extract any error details.
var db = require('arangojs')("http://127.0.0.1:8529");
/*
The '_system' database contains a collection called 'test' that contains one document:
{
"a": 1,
"b": 2
}
*/
// This works
db.query('FOR t IN test FILTER t.a == 1 RETURN t')
.then((cursor) => {
cursor.all()
.then(vals => {
console.log("\nNo bindVars");
console.log(vals);
});
});
// This does not work
db.query("FOR t IN #first FILTER t.a == #second RETURN t", { first: "test", second: 1 })
.then((cursor) => {
cursor.all()
.then(vals => {
console.log("\nUsing bindVars");
console.log(vals);
});
});
I'm new to Node.js and ArangoDB and would love to be able to use properly parameterized queries.
I'm also assuming that this use of parameters protects you from SQL Injection style attacks?
Thanks!
The problem isn't with the JavaScript driver or Node, the problem is with the query itself:
FOR t IN #first FILTER t.a == #second RETURN t
In AQL collection names can't be injected with ordinary bind parameters. This is because you're not actually trying to use the parameter as a string value but to refer to a collection with that name. To quote the AQL documentation:
A special type of bind parameter exists for injecting collection names. This type of bind parameter has a name prefixed with an additional # symbol (thus when using the bind parameter in a query, two # symbols must be used).
In other words, in AQL it has to be called ##first (instead of #first) and in the bind parameters argument to db.query it has to be called #first (instead of just first).
When using arangojs it's actually possible to avoid this entirely by using the aqlQuery template handler:
var aqlQuery = require('arangojs').aqlQuery;
var first = db.collection('test');
var second = 1;
db.query(aqlQuery`
FOR t IN ${first}
FILTER t.a == ${second}
RETURN t
`).then(
cursor => cursor.all()
).then(vals => {
console.log('Using aqlQuery');
console.log(vals);
});
This way you don't have to think about bind parameter syntax when writing queries and can write more complex queries without having to mess with extremely long strings. Note that it will recognize arangojs collection instances and handle them accordingly. Using a string instead of a collection instance would result in the same problems as in your example.
Additionally note that the template handler also exists in the arangosh shell and in ArangoDB itself (e.g. when using Foxx).
The following is confusing me a lot. I have been spending quite a bit of time trying to understand why collection.find() doesn't work with regex passed as an object. The regex match is coming over HTTP wrapped in the body of a POST request. Then I try to gather the query (in string format) and perform the query. The problem seems to be that unless the regex is written inside Node without quotes, it won't work. That is, it must be a literal without quotes.
For example, the following works fine:
var query1 = {
company: {
'$regex': /goog/
}
};
collection.find(query1, {}).toArray(function (err, docs) {
// Got results back. Awesome.
});
However, if the data comes wrapped in an object, it doesn't return anything. I suspect it's because the value gets quoted behind the scenes (i.e. "/goog/"):
// Assume
var query2 = {
company: {
'$regex': query.company
}
};
collection.find(query2, {}).toArray(function (err, docs) {
// Got nothing back.
});
I have tested it with the mongo shell and I can confirm the following:
// Returns 5 results
db.getCollection("contacts").find( { "company": /goog/ } )
// Doesn't match anything
db.getCollection("contacts").find( { "company": "/goog/" } )
Furthermore, I just discovered the following: if I write the value with quotes
// Works fine
var companyRegex = {'$regex': /goog/};
var query3 = {
company: companyRegex
};
So technically, a "literal" regex without quotes wrapped in an object works fine. But if it's a string, it won't work. Even after trying to replace the double-quotes and single-quotes with nothing (i.e. essentially removing them.)
Any idea how can I get the regex match be passed verbatim to find()? I've researched it, finding lots of potential solutions, alas it's not working for me.
Thanks in advance!
Let me focus on one line of your post. This is where the problem might be:
The regex match is coming over HTTP wrapped in the body of a POST request.
This seems problematic because:
The only structures that survive serialization between client/server are:
boolean
number
string
null *
objects and arrays containing these basic types
objects and arrays containing object and arrays [of more obj/array] of these basic types
Regexp, Date, Function, and a host of others require reconstruction, which means
passing a string or pair of strings for the match and option components of the Regexp and running Regexp() on the receiving end to reconstruct.
Regexp gets a bit messy because Regexp.toString() and Regexp() do not appear to be inverses of each others: /someMatch/.toString() is "/someMatch/" but RegExp("/someMatch/") is //someMatch// and what was needed instead to rebuild the regexp was just RegExp("someMatch"), which is /someMatch/. I hope this helps.
JSON.stringify(/someMatch/) is {} (at least on Chrome).
So instead of trying to build a general transport, I recommend re instantiating a particular field as a regexp.
* Irrelevant note: (null is fine but undefined is peculiar. JSON won't stringify undefineds in objects and turns undefined into null in Arrays. I recognize this isn't part of your problem, just trying to be complete in describing what can be serialized.)