Orientdb NoSQL conditionally execute a query - nosql

I'm using the OrientDB REST API and am trying to find a way to check for an edge and create it if it does not exist using only one POST request. Multiple queries and commands are fine, just want to minimize the overhead created by back and forth with the server.
I have written a query to check for the edge in OrientDB's built in Tolkien-Arda dataset:
SELECT IF(COUNT(*) FROM
(SELECT FROM Begets
WHERE OUT IN (SELECT FROM Creature WHERE uniquename='rosaBaggins')
AND IN IN (SELECT FROM Creature WHERE uniquename='adalgrimTook')) > 0, "True", "False")
This ugly monstrosity of a query just counts how many edges are going from rosaBaggins to adalgrimTook and returns "true" if it returns more than 0 and false otherwise.
However I'm not sure how to go the next step and execute the CREATE EDGE query if true. Help appreciated with this or with writing my insane query more efficiently, I get the feeling that I've done it the hard way.

If you want you can do that through Java API, this code check if an outgoing edge from rosaBaggins to adalgrimTook exist:
String DB = "<db name>";
String path = "remote:localhost/" + DB;
OServerAdmin serverAdmin;
try
{
serverAdmin = new OServerAdmin(path).connect("<username>", "<password>");
if(serverAdmin.existsDatabase())
{
OrientGraphFactory factory = new OrientGraphFactory(path);
OrientGraph g = factory.getTx();
Iterable<Vertex> result = g.command(new OCommandSQL("SELECT FROM #18:0 WHERE out().uniquename contains 'adalgrimTook'")).execute();
List<Vertex> list = new ArrayList<Vertex>();
CollectionUtils.addAll(list, result.iterator());
if(list.size() == 0)
{
System.out.println("Edge doesn't exist, I'm creating it ...");
g.command(new OCommandSQL("CREATE EDGE connection FROM (SELECT FROM Creature WHERE uniquename = 'rosaBaggins') TO (SELECT FROM Creature WHERE uniquename = 'adalgrimTook')")).execute();
}
else
{
System.out.println("Edge already exist");
}
serverAdmin.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
Hope it helps
Regards

Since it was not mentioned to be in Java I'll just provide you the pure SQL implementation of this edge Upsert
let $1 = select from user where _id = 'x5mxEBwhMfiLSQHaK';
let $2 = select expand(both('user_story')) from story where _id = '5ab4ddea1908792c6aa06a93';
let $3 = select intersect($1, $2);
if($3.size() > 0) {
return 'already inserted';
}
create edge user_story from (select from user where _id = 'x5mxEBwhMfiLSQHaK') to (select from story where _id = '5ab4ddea1908792c6aa06a93')
return 'just inserted';
I did not use the original code from the tolkien-Arda, but feel free to fill that code in.
The structure consists of a user and a story written by him. If they aren't linked yet an edge (user_story) is created.

Using part of #mitchken 's answer, I've figured it out.
LET $1 = SELECT expand(bothE('Begets')) from Creature where uniquename='asdfasdf';\
LET $2 = SELECT expand(bothE('Begets')) FROM Creature WHERE uniquename='adalgrimTook';\
LET $3 = SELECT INTERSECT($1, $2);\
LET $4 = CREATE EDGE Begets FROM (SELECT FROM Creature WHERE uniquename='asdfasdf') TO (SELECT FROM Creature WHERE uniquename='adalgrimTook');\
SELECT IF($3.INTERSECT.size() > 0, 'Already exists', $4)
Sending this script to the server the first time creates a new edge between 'asdfasdf' (a vertex I just created) and 'adalgrimTook', and returns the #rid of the new edge. The second time I send the script to the server, it returns 'Already exists'.
Also important to note (took me a lot of frustration to figure this out) is that the LET statements will not work in the CLI or Browse tab on the web GUI, but work just fine as a POST script.

Related

How to create a single repository for all queries using ADO.net and MVC

since im using npgsql and postgressql creating model from my database is a big pain,there are man views and adding views to model using npgsql is a big pain which is not solved yet,any way for some reasons I need to use ado,is there any possibility to have a single gate for all my transactions?i have the following code in my controller:
Here I have my connection:
NpgsqlConnection npgc = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Central"].ConnectionString);
npgc.Open();
NpgsqlCommand cmd = new NpgsqlCommand(#"SELECT xc.m_error_group_name, xc.m_error_group_id, count(*),error_duration
FROM (
SELECT extract(year from m_date) m_year, v1.m_error_group_name, v1.m_error_group_id,
zd.t_users g on(g.user_id=f.pv_person_resp_id) and g.user_name in(#rgnal)
LEFT OUTER JOIN ssw_mdt.t_master_pc_alarm_pattern t3 ON (t1.m_inv_error_details = t3.pc_group_pattern)
WHERE (m_date between #fr and #to)
AND t1.crew_present is FALSE
AND t1.m_grid_loss is FALSE
) GROUP BY 1, 2
order by error_duration desc", npgc);
here is how I query:
NpgsqlParameter[] param = {new NpgsqlParameter("#rgnal",reginalManagers),
new NpgsqlParameter("#fr",dtFrom),
new NpgsqlParameter("#to",dtTo);
cmd.Parameters.AddRange(param);
FaultStatViewModel flt = new FaultStatViewModel();
using (NpgsqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
flt.m_error_group_name.Add(rdr["m_error_group_name"].ToString());
}
}
npgc.Close();
so imagine I have 10 other queries I don't want to do these all again and again,please help me out,im new

Titan index issues with Cassandra storage backend

I am populating a Titan 1.0.0 single instance with a moderate graph in order to test its query performance. I am using Cassandra 2.0.17 as storage backend.
The thing is I am not able to create node indexes, and hence query results optimally. I have read the docs and I am trying to follow them carefully without much success. I am using the following groovy script for the schema definition, data population and index creation:
import com.thinkaurelius.titan.core.*;
import com.thinkaurelius.titan.core.schema.*;
import com.thinkaurelius.titan.graphdb.database.management.ManagementSystem;
import java.time.temporal.ChronoUnit;
graph = TitanFactory.open('conf/my-titan.properties');
mgmt = graph.openManagement();
// Build graph schema
// Node properties
idProp = mgmt.containsPropertyKey('userId') ?
mgmt.getPropertyKey('userId') : mgmt.makePropertyKey('id').dataType(String.class).cardinality(Cardinality.SINGLE);
isPublicProp = mgmt.containsPropertyKey('isPublic') ?
mgmt.getPropertyKey('isPublic') : mgmt.makePropertyKey('isPublic').dataType(Boolean.class).cardinality(Cardinality.SINGLE);
completionPercentageProp = mgmt.containsPropertyKey('completionPercentage') ?
mgmt.getPropertyKey('completionPercentage') : mgmt.makePropertyKey('completionPercentage').dataType(Integer.class).cardinality(Cardinality.SINGLE);
genderProp = mgmt.containsPropertyKey('gender') ?
mgmt.getPropertyKey('gender') : mgmt.makePropertyKey('gender').dataType(String.class).cardinality(Cardinality.SINGLE);
regionProp = mgmt.containsPropertyKey('region') ?
mgmt.getPropertyKey('region') : mgmt.makePropertyKey('region').dataType(String.class).cardinality(Cardinality.SINGLE);
lastLoginProp = mgmt.containsPropertyKey('lastLogin') ?
mgmt.getPropertyKey('lastLogin') : mgmt.makePropertyKey('lastLogin').dataType(String.class).cardinality(Cardinality.SINGLE);
registrationProp = mgmt.containsPropertyKey('registration') ?
mgmt.getPropertyKey('registration') : mgmt.makePropertyKey('registration').dataType(String.class).cardinality(Cardinality.SINGLE);
ageProp = mgmt.containsPropertyKey('age') ? mgmt.getPropertyKey('age') : mgmt.makePropertyKey('age').dataType(Integer.class).cardinality(Cardinality.SINGLE);
mgmt.commit();
nUsers = 0
println 'Starting nodes population...';
// Load users
new File('/home/jarandaf/soc-pokec-profiles.txt').eachLine {
try {
fields = it.split('\t').take(8);
userId = fields[0];
isPublic = fields[1] == '1' ? true : false;
completionPercentage = fields[2]
gender = fields[3] == '1' ? 'male' : 'female';
region = fields[4];
lastLogin = fields[5];
registration = fields[6];
age = fields[7] as int;
graph.addVertex('userId', userId, 'isPublic', isPublic, 'completionPercentage', completionPercentage, 'gender', gender, 'region', region, 'lastLogin', lastLogin, 'registration', registration, 'age', age);
} catch (Exception e) {
// Silently skip...
}
nUsers += 1
if (nUsers % 100000 == 0) println String.valueOf(nUsers) + ' loaded...';
};
graph.tx().commit();
println 'Nodes population finished';
// Index users by userId, gender and age
println 'Getting node properties...';
mgmt = graph.openManagement();
userId = mgmt.getPropertyKey('userId');
gender = mgmt.getPropertyKey('gender');
age = mgmt.getPropertyKey('age');
println 'Building byUserId index...';
if (mgmt.getGraphIndex('byUserId') == null) mgmt.buildIndex('byUserId', Vertex.class).addKey(userId).buildCompositeIndex();
println 'Building byGender index...';
if (mgmt.getGraphIndex('byGender') == null) mgmt.buildIndex('byGender', Vertex.class).addKey(gender).buildCompositeIndex();
println 'Building byAge index...';
if (mgmt.getGraphIndex('byAge') == null) mgmt.buildIndex('byAge', Vertex.class).addKey(age).buildCompositeIndex();
mgmt.commit();
// Wait for the indexes to become available
println 'Awaiting byUserId graph index status...';
ManagementSystem.awaitGraphIndexStatus(graph, 'byUserId')
.status(SchemaStatus.REGISTERED)
.timeout(10, ChronoUnit.MINUTES)
.call();
println 'Awaiting byGender graph index status...';
ManagementSystem.awaitGraphIndexStatus(graph, 'byGender')
.status(SchemaStatus.REGISTERED)
.timeout(10, ChronoUnit.MINUTES)
.call();
println 'Awaiting byAge graph index status...';
ManagementSystem.awaitGraphIndexStatus(graph, 'byAge')
.status(SchemaStatus.REGISTERED)
.timeout(10, ChronoUnit.MINUTES)
.call();
// Reindex the existing data
mgmt = graph.openManagement();
println 'Reindexing data by byUserId index...';
mgmt.updateIndex(mgmt.getGraphIndex('byUserId'), SchemaAction.REINDEX).get();
println 'Reindexing data by byGender index...';
mgmt.updateIndex(mgmt.getGraphIndex('byGender'), SchemaAction.REINDEX).get();
println 'Reindexing data by byAge index...';
mgmt.updateIndex(mgmt.getGraphIndex('byAge'), SchemaAction.REINDEX).get();
mgmt.commit();
// Enable indexes
println 'Enabling byUserId index...'
mgmt.awaitGraphIndexStatus(graph, 'byUserId').status(SchemaStatus.ENABLED).call();
println 'Enabling byGender index...'
mgmt.awaitGraphIndexStatus(graph, 'byGender').status(SchemaStatus.ENABLED).call();
println 'Enabling byAge index...'
mgmt.awaitGraphIndexStatus(graph, 'byAge').status(SchemaStatus.ENABLED).call();
graph.close();
The error I am getting is the following and is related with the reindex phase:
08:24:26 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - Evicted [2#0ac717511509-mybox] from cache but waiting too long for transactions to close. Stale transaction alert on: [standardtitantx[0x4b8696a4], standardtitantx[0x2d39f30a], standardtitantx[0x0da9172d], standardtitantx[0x7c6c7909], standardtitantx[0x79dd0a38], standardtitantx[0x5999c49e], standardtitantx[0x5aaba4a7]]
08:24:26 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - Evicted [3#0ac717511509-mybox] from cache but waiting too long for transactions to close. Stale transaction alert on: [standardtitantx[0x4b8696a4], standardtitantx[0x2d39f30a], standardtitantx[0x0da9172d], standardtitantx[0x7c6c7909], standardtitantx[0x79dd0a38], standardtitantx[0x5999c49e], standardtitantx[0x5aaba4a7]]
08:24:26 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - Evicted [4#0ac717511509-mybox] from cache but waiting too long for transactions to close. Stale transaction alert on: [standardtitantx[0x4b8696a4], standardtitantx[0x2d39f30a], standardtitantx[0x0da9172d], standardtitantx[0x7c6c7909], standardtitantx[0x79dd0a38], standardtitantx[0x5999c49e], standardtitantx[0x5aaba4a7]]
Any hints on this would be much appreciated.
The errors you get indicate that you have open transactions when you try to modify the schema. Titan needs to wait for all transactions to complete before it can modify the schema. See the answer from Matthias Broecheler on the mailing list for more information.
In general, you should avoid reindexing if possible as it requires Titan to walk over all vertices to see whether they need to be added to the index that should be updated. The documentation contains more information about this process.
For your use case, you can simply create all indexes before you load any data. When you then add the data after all indexes are ready, they will be simply added to the indexes. That way, you should be able to use the indexes immediately.
A minimal example for the schema creation in Groovy (but it should be basically the same in Java):
import com.thinkaurelius.titan.core.TitanFactory;
import com.thinkaurelius.titan.core.Multiplicity;
import com.thinkaurelius.titan.core.Cardinality;
graph = TitanFactory.open('conf/my-titan.properties')
mgmt = graph.openManagement()
id = mgmt.makePropertyKey('id').dataType(String.class).cardinality(Cardinality.SINGLE)
// some other properties that will not be indexed
mgmt.makePropertyKey('isPublic').dataType(Boolean.class).cardinality(Cardinality.SINGLE)
mgmt.makePropertyKey('completionPercentage').dataType(Integer.class).cardinality(Cardinality.SINGLE)
// I prefer to use vertex labels to differentiate between different 'types' of vertices but this isn't necessary
User = mgmt.makeVertexLabel('User').make()
mgmt.buildIndex('UserById',Vertex.class).addKey(id).indexOnly(user).buildCompositeIndex()
mgmt.commit()
I removed all the checks for already existing schema elements for simplicity, but you can of course add them again.
After the schema creation, you can add your data just like before.
A final node about index management: Try to always define the property keys that you want to index in the same transaction in which you create the index. Otherwise, Titan cannot know whether there is already data that needs to be added to the new index which requires again a complete scan of all data. This might require to choose a different name for a property. When you add for example a new vertex label post, then you might want to use a new name like postId instead of using the property id again to avoid the scan of all existing data.

Find and delete duplicate edges in OrientDb

Consider we have Vertex User and Edge FriendsWith.
FriendsWith can be in both directions out and in (usually it is either out or in between 2 users).
Duplicates are when either out or in from one user to another is found more then one time (out and in together is not considered as duplicate)
Is there any way to find duplicate edges and delete them?
UPDATE Added picture illustrating problem
Thank you.
here is my javascript function:
var g=orient.getGraph();
var C=g.command('sql','select from FriendsWith');
var arr = new Array(C.length);
var toRemove = new Array();
for(i=0;i<C.length;i++){
var found = false;
for (x = 0; x < i+1 && !found; x++) {
if (arr[x] === C[i].getProperty("out").getId()+" "+C[i].getProperty("in").getId()) {
found = true;
toRemove.push(C[i].getId());
}
}
arr[i] = C[i].getProperty("out").getId()+" "+C[i].getProperty("in").getId();
}
for(a=0;a<toRemove.length;a++){
var C=g.command('sql','delete edge '+toRemove[a]);
}
Hope it helps.
Bye
You can try this function
var g=orient.getGraph();
var friends=g.command("sql","select from FriendsWith");
var paths=[];
for(i=0;i<friends.length;i++){
paths.push(friends[i]);
}
for(i=0;i<paths.length;i++){
var myEdge=paths[i];
var vIn=myEdge.getProperty("in").getId();
var vOut=myEdge.getProperty("out").getId();
for(j=0;j<paths.length;j++){
if(i<j){
var edge=paths[j];
var vInCopy=edge.getProperty("in").getId();
var vOutCopy=edge.getProperty("out").getId();
if((vIn==vInCopy && vOut==vOutCopy) || (vIn==vOutCopy && vOut==vInCopy)){
g.command("sql","delete edge FriendsWith where #rid="+edge.getId());
paths.splice(j, 1);
j--;
}
}
}
}
Before
After
I created a small DB to try your case. This is my code:
create class User extends V
create class follows extends E
create property User.id integer
create property User.name String
create vertex User set id=1, name="Paul"
create vertex User set id=2, name="John"
create vertex User set id=3, name="Mark"
create vertex User set id=4, name="Robert"
create edge follows from (select from User where id=1) to (select from User where id=2)
create edge follows from (select from User where id=2) to (select from User where id=1)
create edge follows from (select from User where id=1) to (select from User where id=3)
create edge follows from (select from User where id=2) to (select from User where id=3)
create edge follows from (select from User where id=3) to (select from User where id=2)
create edge follows from (select from User where id=3) to (select from User where id=4)
Graph:
Then I created a simple Javascript function which deletes, once found a duplicated edge, the in-direction edge.
Input: ridA (yout starting #rid)
Code:
var g=orient.getGraph();
var outF=g.command('sql','select expand(out("follows")) from '+ridA);
var inF=g.command('sql','select expand(in("follows")) from '+ridA);
for(x=0;x<outF.length;x++){
var ridOut=outF[x].getId();
for(y=0;y<inF.length;y++){
var ridIn=inF[y].getId();
if(ridOut==ridIn){
g.command('sql','delete edge follows from '+ridIn+' to '+ridA);
}
}
}
Edit:
For example, if you try to delete the duplicated edges from the vertex #12:1, after having launched the function the two in-direction edges 'follow' will be deleted.

Apex Trigger to Update Contact from Custom Object

Long story short, I need to update a custom field in my standard Contact, that fires after a different, unrelated Custom Object is updated. I've tried to write a trigger that passes the field value from my Custom Object to the Contact, but I keep getting a variety of errors - the most recent of which has stumped me. The end goal is to update Passing__c from Passing_Field__c.
I'm getting an unexpected Token: "(" error on the for(Contact C: line. It is literally so simple I cannot figure it out.
Here is my code below. I've simplified the naming convention to try and make it more relatable. Any help is appreciated. I'm pretty new to Apex and Triggers, and I've been at this for a couple of hours now, hopefully some advice can send me to 'home plate'.
trigger ContactUpdater on Custom_Object_Name__c (after update) {
List<Contact> updatedContacts = new List<Contact>();
Set<Id> ObjectIds = new Set<Id>();
Set<String> ObjectCont = new Set<String>();
Set<Boolean> ObjectActive = new Set<Boolean>();
Set<String> ObjectPass = new Set<String>();
for(Custom_Object_Name__c p : trigger.new)
{
If(p.Active__c == true){
ObjectIds.add(p.Id);
ObjectCont.add(p.Contact__c);
ObjectActive.add(p.Active__c);
ObjectPass.add(p.Passing_Field__c);
}
try{ for(Contact c : [SELECT Id, Passing__c FROM Contact WHERE (AccountId IN (Select Account__c from Custom_Object_Name__c )) AND ObjectActive = true])
{
set(c.Passing__c = p.Passing_Field__c);
c.FieldToUpdate = c.Passing__c;
updatedContacts.add(c);
}
update updatedContacts;
}
catch(exception e){
throw e;
}
}
}
Notes: Active__c is a checkbox. Passing__c and Passing_Field__c are both text boxes.
I believe the issue is in the WHERE clause of your SOQL query:
WHERE (AccountId = (Select Account__c from Custom_Object_Name__c ))
Salesforce is expecting you to compare AccountId to an Id of some sort, rather than the results of some subquery. You probably want to try something like:
WHERE (AccountId in (Select Account__c from Custom_Object_Name__c))

Extending Zend_Db

I apologize if my title is a bit misleading and it turns out that it's some other class under Zend_Db.
I use the following method of extracting data from a MSSQL:
// $_config contains information about how to connect to my MSSQL server
$config = new Zend_Config($_config);
$db = Zend_Db::factory($config->database);
$sql = "SELECT * FROM table1";
print_r($db->fetchAll($sql));
So far no problem and everything runs smooth :).
Now I need to run some more complex queries with multiple rowsets:
$sql2 = <<<EOD
DECLARE #test INT
SET #test = 42
SELECT * FROM table1 WHERE col1 = #test
SELECT col2 FROM table2 UNION
SELECT col3 FROM table2
SELECT * FROM table3
EOD;
print_r($db->fetchAll($sql2));
I hope you get the idea.
Using $db->fetchAll($sql2); will result in
Fatal error: Uncaught exception
'Zend_Db_Statement_Exception' with
message 'SQLSTATE[HY000]: General
error: 10038 Attempt to initiate a new
SQL Server operation with results
pending. [10038] (severity 7)
[(null)]' in
\Sacp026a\sebamweb$\prod\includes\Zend\Db\Statement\Pdo.php:234
The following function will return all the correct rowsets:
function sqlquery_multiple($zdb, $sql) {
$stmt = $zdb->query($sql);
$rowsets = array();
do {
if ($stmt->columnCount() > 0) {
$rowsets[] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
} while ($stmt->nextRowset());
return $rowsets;
}
print_r(sqlquery_multiple($db, $sql2));
Now my big question is:
How do I extend Zend_Db, so I can implement and use the function above as $db->fetchMulti($sql2); instead of sqlquery_multiple($db, $sql2)?
Thanks in advance :)
NB: It's worth mentioning that I'm using the ODBC-patch in order to be able to fetch multiple rowsets in the first place.