bulk Insert or Update Vertex property using blueprints -OrientDB - orientdb

I am using OrientDB 2.1.4 and blueprints-core-2.6.0.
I have a requirement to update values on an existing Vertex or creating a new Vertex if not present. (expected 30k vertices every 45 seconds)
My vertex class is : Device(Name, Type, ActiveSessionCount) - "Name" for each Device is a unique entity.
Need to update ActiveSessionCount on device if device exists, else create a new Device vertex.
if (graph.getVertices(keyName, key).iterator().hasNext()) {
vertex = (OrientVertex) graph.getVertices(keyName, key).iterator().next();
} else {
vertex = graph.addVertex(className, attributeName, key);
}
I am trying to check if a vertex exists, if a vertex already exists, I have fetched the Vertex object for further update, else created a new Vertex Object.
Although, this works, it is taking a couple of minutes to execute for 30k records, while I need to achieve the same in 45 seconds.

Try with UPSERT.
UPSERT updates a record if it already exists, or inserts a new record if it does not, all in a single statement.
g.command(new OCommandSQL("update Device set Name='Device 3',Type='Type 3',ActiveSessionCount=3 upsert where Name='Device 3'' "));
Regards,
Michela

Related

Orientdb getVertices() returing Vertex for any label present in database

I am using Orientdb 2.2.10.
What I want to achieve?
I want to get a vertex of a particular vertexType
- e.g vertexType = 'Person'.
My graphdb is indexed with unique key('uid').
What I am doing to achieve it?
getVertices(lable, []iKey, []iValue)
I am getting the desire vertex
what is problem with this method? :-
I am getting the desire vertex even when I provide any label(which is present in the database) name
e.g:-
I want to get a vertex of vertextype = 'Person' having uid = 'ram'
I am getting this vertex even when I provide any label (e.g "Relation") which is present in database.
Is this a bug or I am doing something wrong?
Thanks..!
I replicated your structure.
I have tried with this code
String [] keys=new String[]{"uid"};
String [] values=new String[]{"ram"};
Iterable<Vertex> it= g.getVertices("Person", keys, values);
for(Vertex v:it){
System.out.println(v.getId());
System.out.println(v.getProperty("uid"));
}
and I obtained
#21:0
ram
while with
String [] keys=new String[]{"uid"};
String [] values=new String[]{"ram"};
Iterable<Vertex> it= g.getVertices("Relational", keys, values);
for(Vertex v:it){
System.out.println(v.getId());
System.out.println(v.getProperty("uid"));
}
I got nothing.
Hope it helps.

Tinkerpop Frames #Adjacency to Orientdb LINKLIST

Is there a way to map Tinkerpop Frames's #Adjacency annotated property to Orientdb LINKLIST? Right now I've something like this:
interface Person {
#Adjacency(label = "personCars", direction = Direction.OUT)
Iterable<Car> getCars();
#Adjacency(label = "personCars", direction = Direction.OUT)
void addCar(Car car);
}
I want this to be mapped to LINKLIST in Orientdb database to keep an order of added vertices. But this is by default mapped to LINKBAG type. Is there any clean solution to set Orientdb to map adjacencies to LINKLISTs?
OrientDB, by default, uses a set to handle the edge collection. Sometimes it's better having an ordered list to access the edge by an offset. Example:
person.createEdgeProperty(Direction.OUT, "Photos").setOrdered(true);
Every time you access the edge collection the edges are ordered. Below is an example to print all the photos in an ordered way.
for (Edge e : loadedPerson.getEdges(Direction.OUT, "Photos")) {
System.out.println( "Photo name: " + e.getVertex(Direction.IN).getProperty("name") );
}
To access the underlying edge list you have to use the Document Database API. Here's an example to swap the 10th photo with the last.
// REPLACE EDGE Photos
List<ODocument> photos = loadedPerson.getRecord().field("out_Photos");
photos.add(photos.remove(9));
From the official documentation.

ArangoDB create Vertex REST API without knowing the vertex id's

Is there a way to create with ArangoDB an Edge with REST API without knowing the Vertex ids? With a query to find the vertexs and link them?
Like this with OrientDB: create edge Uses from (select from Module where name = 'm2') to (select from Project where name = 'p1')
I don't want to query via REST the two vertex before, and after create the Edge. I don't want to use Foxx also.
Perhaps with AQL?
Thanks.
Yes, it is doable with a single AQL query:
LET from = (FOR doc IN Module FILTER doc.name == 'm2' RETURN doc._id)
LET to = (FOR doc IN Project FILTER doc.name == 'p1' RETURN doc._id)
INSERT {
_from: from[0],
_to: to[0],
/* insert other edge attributes here as needed */
someOtherAttribute: "someValue"
}
INTO nameOfEdgeCollection

Compile error when trying to make rollup apex trigger

Been amending a piece of code to suit my needs but it won't compile. My naive eyes cannot see the error of my ways:
trigger doRollup on Time_Record__c (after insert, after update, after delete, after undelete) {
// List of parent record ids to update
Set<Id> parentIds = new Set<Id>();
// In-memory copy of parent records
Map<Id,Time_Record__c> parentRecords = new Map<Id,Time_Record__c>();
// Gather the list of ID values to query on
for(Daily_Time_Record__c c:Trigger.isDelete?Trigger.old:Trigger.new)
parentIds.add(c.Time_Record_Link__c);
// Avoid null ID values
parentIds.remove(null);
// Create in-memory copy of parents
for(Id parentId:parentIds)
parentRecords.put(parentId,new Time_Record__c(Id=parentId,RollupTarget__c=0));
// Query all children for all parents, update Rollup Field value
for(Daily_Time_Record__c c:[select id,FieldToRoll__c,Time_Record_Link__c from Daily_Time_Record__c where id in :parentIds])
parentRecords.get(c.Time_Record_Link__c).RollupTarget__c += c.FieldToRoll__c;
// Commit changes to the database
Database.update(parentRecords.values());
}
Where:
Time_Record__c is my parent
RollUpTarget__c is the place I am trying to roll to
Daily_Time_Record__c is the child
Time_Record_Link__c is the link to parent that exists on the child
FieldToRoll__c is a test field to roll up on the child
I think that is what I had to replace from this generic template:
trigger doRollup on Child__c (after insert, after update, after delete, after undelete) {
// List of parent record ids to update
Set<Id> parentIds = new Set<Id>();
// In-memory copy of parent records
Map<Id,Parent__c> parentRecords = new Map<Id,Parent__c>();
// Gather the list of ID values to query on
for(Child__c c:Trigger.isDelete?Trigger.old:Trigger.new)
parentIds.add(c.ParentField__c);
// Avoid null ID values
parentIds.remove(null);
// Create in-memory copy of parents
for(Id parentId:parentIds)
parentRecords.put(parentId,new Parent__c(Id=parentId,RollupField__c=0));
// Query all children for all parents, update Rollup Field value
for(Child__c c:[select id,Amount__c,ParentField__c from Child__c where id in :parentIds])
parentRecords.get(c.ParentField__c).RollupField__c += c.Amount__c;
// Commit changes to the database
Database.update(parentRecords.values());
}
Ideally I want to roll up a sum of 7 fields from the child (hence needing this solution), but starting small.

Why "EntityKey does not match the corresponding value in the EntityKey"?

First I'd like to show the corresponding code snippet. When it comes to objCtx.AttachTo() it throws me an error:
Error: "The object cannot be attached because the value of a property that is a part of the EntityKey does not match the corresponding value in the EntityKey."
// convert string fragIds to Guid fragIds
var fragIdsGuids = docGenResult.FragIds.Select(c => new Guid(c)).ToList();
//add each fragment to document))))
foreach (Guid fragIdsGuid in fragIdsGuids)
{
var fragment = new Fragment() { EntityKey = new EntityKey("DocTestObjectContext.Fragments", "ID", fragIdsGuid) };
objCtx.AttachTo("Fragments", fragment);
}
objCtx.SaveChanges();
I've checked everything and I'm not missing any primary key.
However I need some words to explain why I think I have to do it this way.
I'm using EF4 in a C# Environment.
I have a many to many relationship between two tables, Document and Fragments(Primary key "ID") (Documents can have many fragments and a fragment can be a part of many documents)
The Entity Model works fine for me.
However when I try to add a new document to the DB I already have the IDs of the related Fragments in my hand. For adding a new document to the DB I have to call each Fragmentobject and add it to the mapped reference in my document-object. This is a bottleneck because a document can have more than 1000 fragments. The Consequence is that I need 1sec per document. Not much, but I have to create more than 3000 documents and saving this second would result in more speed.
Hopefully you know what's wrong in here.
Thanks.
Thomas
1st edit:
here is the solution wich actually works. I would like to avoid to load all the fragments and instead just save the fragment GUID I already have in the mapping table.
// convert string fragIds to Guid fragIds
var fragIdsGuids = docGenResult.FragIds.Select(c => new Guid(c)).ToList();
// get responding entities from Fragment table
var fragmentList = objCtx.Fragments.Where(c => fragIdsGuids.Contains(c.ID)).ToList();
foreach (var fragment in fragmentList)
{
doc.Fragment.Add(fragment);
}
objCtx.SaveChanges();
2nd edit:
I have the feeling that it is not really clear what I try to do.
However I would like to link/reference existing fragments in a Fragment-table to a coressponding Document in a Document table. The Document I'd like to reference is a new one. The document to Fragment table has an many to many relationship. This relationship has a linking table on the database. In the model it is correctly modeled as a many to many relationship. That's fine.
So far so good. What works is what you can see under my first edit. I have to load all the necessary fragments for a document by their id
// get responding entities from Fragment table
var fragmentList = objCtx.Fragments.Where(c => fragIdsGuids.Contains(c.ID)).ToList();
After that I'm able to add them to my document entity:
foreach (var fragment in fragmentList)
{
doc.Fragment.Add(fragment);
}
But why the hell do I have to load the whole entity (fragments) only to link it to a new document. Why do not tell the EntityStateManager "Dude, here you have some Fragment IDs, link them!"?
Further I tried to follow the MSDN article mentioned by Adrian in the comments. This doesn't worked out for me.
I'll try this:
var fragment = new Fragment {ID = fragIdsGuid};
//fragment.EntityKey.Dump(); // -- this should be null
objCtx.AttachTo("Fragments", fragment);
//fragment.EntityKey.Dump(); // -- shows the EntityKey object, created after the object is attached
The Dump function is from LinqPad