How to use array results from orientjs query in another query - array is not an "array" - orientdb

I want to use an array-like result from a query, but am having trouble.
I have:
class case extends V
class doc extends V
class filedIn extends E
So, a document is filed in a class via an edge of class filedIn.
My first query pulls a set a vertices:
.select().from('case').one().then(function(result){...
I then want to select all the filedIn edges linking to any of those case vertices, but how?
JSON.stringify(result)
{"#type":"d","#class":"matter","title":"my case","in_filedIn":["#17:7","#17:8","#17:9"],"#rid":"#12:3","#version":12}
looks like result['in_filedIn'] is an array,
but
.select().from(result['in_filedIn']).all()
gets me this error from back from the database:
Error on parsing command at position #0: Error parsing query: \nSELECT * FROM [object Object]\nEncountered \
select().from('[#17:7,#17:8,#17:9]')
(hard coded) works.
.select.from("[" + ["#17:1","#17:2].join(',') + "]").all()
also works.
but
select.from("[" + result['in_filedIn'].join(,)+"]").all()
throws
result.in_filedIn.join is not a function
I.e. whatever kind of object it is, it's not inheriting from the Array prototype.
console.log(result['in_filedIn'])
produces:
Bag {
serialized: >'AQAAAAUAEQAAAAAAAAAHABEAAAAAAAAACAARAAAAAAAAAAkAEQAAAAAAAAAKABEAAAAAAAAADwAAAAA>AAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
uuid: null,
_content:
[ { [String: '#17:7'] cluster: 17, position: 7 },
...
So I'm rather puzzled what to do.
I want to select all the edges whose #rid is listed in result.in_filedIn
Or have I misunderstood something?

Hi oliver in_filedIn is not an Array is a structure called RidBag in Orientjs the implementation is done in Bag.js.
If yo want to get the array you should do
result['in_filedIn'].all()
to get the array.

The following worked, though it's a bit dirty.
.from(JSON.stringify(result['in_filedIn']).replace(/"/g,""))
I'm still looking for a better answer!

I had a similar problem actually. When you instantiate your db connection, there's a config field they don't list in their docs called enableRIDBags.
So your config would look like:
{
host: 'localhost',
port: 2424,
username: 'blah',
password: 'blooh',
enableRIDBags: false
}
I find that it's better to just disable RIDBags as they're a bit finicky in node. The .all() trick listed above worked fine for me up until my vertices had more than 40 edges, as then they were all converted to SBTree bags instead of Embedded bags. If you check line 122 here, you'll see that they can't convert the trees to JSON when you call .all()

Related

OrientDB Server Side JavaScript Function: Iterating over array (arraylist)

OrientDB Version: 3.2.6
I wish to create an OrientDB server-side function which zips two arrays into an object, but also format the values (which are always record ids) slightly.
Function name:
idToRidMap
Takes args:
keys - An array of strings representing the keys of the resulting object, Example: ["id1", "id2"]
values - An array of record ids, Example: [#15:1, #15:2]
Returns an object with the id array elements as keys and the record ids as string values without leading "#", i.e. from examples above it would be:
{
"id1": "15:1",
"id2": "15:2"
}
I wish to use this function in queries like this one:
SELECT idToRidMap(configIds, configRids) as configs, * FROM (
SELECT outE("HasConfig").id as configIds, out("HasConfig").#rid as configRids, * FROM 12:0
)
So, depending on the id of the linking Edges and the record-id of the linked Vertices I wish to build one property showing all those relations in the returned record:
{
"#rid": "#12:0",
"someNativeProp": "Hello",
"configs": {
"id1": "15:1",
"id2": "15:2"
},
...
}
Note though, that this would also require me to drop the projections for the intermediate array results as well, extending the query to be something like this:
SELECT idToRidMap(configIds, configRids) as configs, !configIds, !configRids, * FROM (
SELECT outE("HasConfig").id as configIds, out("HasConfig").#rid as configRids, * FROM 12:0
)
The OrientDB JS function definition I've tried (among many others) is:
var result = {};
for (i = 0; i < keys.length; i++) {
result[keys[i]] = String(values[i]).replace('#', '');
}
return result;
But I realized that length is not available (it is undefined) on the keys argument. When testing by using keys.size() (guessing it was java.util.arraylist) I was given an error:
com.orientechnologies.orient.core.command.script.OCommandScriptException: Error on parsing script at position #0: Error on execution of the script Script: idToRidMap ------^ DB name="test" --> javax.script.ScriptException: org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (size) on java.util.ArrayList#1b395482 failed due to: Unknown identifier: size --> org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (size) on java.util.ArrayList#1b395482 failed due to: Unknown identifier: size
Which seems to indicate that it has something to do with graalvm polyglot and that it indeed has to do with java.util.ArrayList. I did check https://www.graalvm.org/22.1/reference-manual/js/JavaInteroperability/#access-java-from-javascript but I'm not sure how relevant it is and I didn't find anything that helped me.
So, to sum up. Basically there's two parts to this question:
Is there any documentation of how the JavaScript server-side functions work type-wise and syntax-wise, etc? It seems really picky to what kind of JavaScript I write as well. How can I do the desired iterations to implement my function?
Is there a better way of achieving my end goal?
Thankful for any insight, I've always had a hard time with OrientDB custom functions.

Apply filtering with an array of value instead of one value for a filter in Algolia

I have in my index a list of object, each of them has an objectID value.
On some search, i want to filter OUT a certain number of them, using there objectID.
For the moment it works with one value as a string, i would like to know how to do for multiple value.
filters = 'NOT objectID:' + objectIDToFilter;
This work for one object, what can i do to apply this for an array of ObjectID. because :
filters = 'NOT objectID:' + arrayObjectID;
does not work.
I was thinking of generating a huge string with an arrayId.map with all my 'NOT objectID:1 AND NOT objectID: 2 ...' but i wanted to know if there is a cleaner way to do it.
I unfortunately misunderstood the line in algolia doc :
Array Attributes: Any attribute set up as an array will match the filter as soon as one of the values in the array match.
This apparently refers to the value itself in Algolia and not the filter
So i did not found a solution on algolia doc, i went for the long string, hope there is no limits on how much filter we can add on a query (found nothing about that).
Here is what i did if someone need it :
let filters = `NOT objectID:${userID}`;
blockedByUsers.map((blockedByUser) => {
filters = filters + ` AND NOT objectID:${blockedByUser}`;
});
If you need to add multiple but don't have a starting point like i do, you can't start the query with an AND , a solution i found to bypass that:
let filters = `NOT objectID:${blockedByUsers[0]}`;
blockedByUsers.map((blockedByUser, i) => {
if (i > 0) filters = filters + ` AND NOT objectID:${blockedByUser}`;
});
There is probably a cleaner solution, but this work. If you have found other solution for that problems i'll be happy to see :)

OrientDB Embedded-List (of String): wildcard query

I can't perform a wildcard-query on an embedded-list property of vertex (or edge).
For example:
Assume we have a Person class with a multi-value property named Nicknames and one instance of it:
{
"#type": "d",
"#rid": "#317:0",
"#version": 1,
"#class": "Person",
"Nicknames": [
"zito",
"ziton",
"zitoni"
]
}
then,
Select FROM Person WHERE Nicknames like "zit%"
returns empty result-set, while:
Select FROM Person WHERE Nicknames ="zito" returns 1 item correctly.
There's a NOTUNIQUE_HASH_INDEX index on the field Nicknames.
I've tried many ways (contains, index-query...) with no luck :(
I'm probably missing something basic.
I know is not an ideal solution what i'm going to write but, to stay stuck with your requirement of "query by wildcard" this is the only way that worked for me, as AVK stated is a better idea work with a Lucene index, but with the standard implementation i was unable to let it work, now here what i've done:
Use studio to create a javascript function with 2 parameter with name "array" and "rule", lets name the function "wildcardSearch"
past this code in the body of the function (is just simple javascript change it if it dosent do the job) :
for(i=0; i<array.length ; i++){
rule= rule.split("*").join(".*");
rule= rule.split("*").join(".*");
rule= "^" + ruleValue + "$";
var regex = new RegExp(rule);
if (regex.test(array[i]))
return true;
}
return false;
Remember to save the fucntion
now you can query:
Select from Person where wildcardSearch(nicknames,'zit*')=true
CONSIDERATIONS: is a brute force method, but show how "funny" can be play around with the "stored procedure" in OrientDb so i've decided to share it anyway, if performance are your main goal this things is not for you, it scan all the class and do the loop on the array to apply the regex. An Index is a way better solution, or change your db with a different data structure.
You can try this:
select from Person where Nicknames containstext 'zit'
Hope that helps

How to insert a vertex with link type property with the orientjs query builder?

I am trying to insert a vertex with orientjs(previously oriento) query builder. My class has a link type property pointing to another class.
I know I can get it to work with a raw query string but I would love to use the query builder.
Here is what I've tried so far :
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"})
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"#33:1289287"})
I get the following error :
Error on saving record in cluster #13
Am I setting properties in the right way ?
Could the error be related to somtehing else ?
I have sucessfully ran an insert query in the cluster #13 with a raw query string in the studio...
According to the official documentation it seems that the problem might be at the end of your statement
db.insert().into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"}).one()
.then(function (data) {
// callback
});
Check if your code works adding one() to the pipe line
EDITED: I found this method in orientjs.
db.create('VERTEX', 'V')
.set({
key: 'value',
foo: 'bar'
})
.one()
.then(function (vertex) {
console.log('created vertex', vertex);
});
When using Tinkerpop API they recommend using createVertex instead of insert, because createVertex is intended for graphs and insert for Documents... Could you try with the create() method instead?
I am using SQL and it worked.
sql = "INSERT INTO Station set linked = (select from LinkedClass where LinkedProb = 'value'), prop = 'value'"
OrientVertex vertex = new OrientVertex();
vertex = graph.command(new OCommandSQL(sql)).execute();
I don't think that's possible unless you've added a proper field with the right type 'Link' in your schema. (which I rarely do).
Now instead of having the right 'link' type inserted you can do the opposite, store is as a String, and leverage the query functions to use it correctly:
db.insert().into('table').set({prop: '#15:14'}).one();
And it will be converted as String (which is a bit sad) but then you can use that in your queries:
SELECT eval(prop) FROM table;
And it will be 'eval'-ed to a Node RecordID that you can directly use and call functions like expand() on.
For example:
SELECT name FROM (SELECT expand(eval(prop)) FROM table);
Will eval the node stored in the insert(), grab the node, expand it and collect its name property.

grails-mongodb: findAllBy*InList not returning results in order

I'm using grails2.4.4 with mongodb plugin version 3.0.3. I'm facing issue while getting results of my domain object. I'm using below code:
My domain:
Employee{
ObjectId id
String name
}
I have list of ids , using below code to fetch employees: (Please note that below data is just for representing my problem. In realtime, my ids are random and so i can't use sorting, but i just want the result in the order of input.)
def idsList=[new ObjectId("2001"), new ObjectId("2002"), new ObjectId("2003")]
def results=Employee.findAllByIdInList(idsList)
Expected result:
[Employee#2001,Employee#2002,Employee#2003]
Actual result (not in order):
[Employee#2002, Employee#2003 , Employee#2001] or sometimes
[Employee#2003, Employee#2001 , Employee#2002]
For now i'm doing like this to get the output in desired order:
def results=[]
for(id in idsList){
def emp=Employee.findById(id)
results<<emp
}
But i want to do this with single call(findAllBy*InList) without iterating over objects. Can anyone advise how can i get the results in the order of input ids?
Have you tried
Employee.findAllByIdInList(idsList, [sort: 'id', order:'asc'])
? It should work as expected
If it doesn't, instead of for loop you can use
def result = idList.collect { id -> Employee.findById(id) }