Find and delete duplicate edges in OrientDb - 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.

Related

Force Entity Framework to read each line with all details

I am having trouble with en EF method returning duplicate rows of data. When I am running this, in my example, it returns four rows from a database view. The fourth row includes details from the third row.
The same query in SSMS returns four individual rows with the correct details. I have read somewhere about EK and problems with optimization when there are no identity column. But - is there anyway to alter the below code to force EK to read all records with all details?
public List<vs_transactions> GetTransactionList(int cID)
{
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}
Found the solution :) MergeOption.NoTracking
public List<vs_transactions> GetTransactionList(int cID)
{
db.vs_transactions.MergeOption = MergeOption.NoTracking;
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}

Orientdb NoSQL conditionally execute a query

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.

Stock Inventory - Send email when cell value < 2 (Google Spreadsheet)

I currently trying to create for stock inventory of some products that are frequently used in my workplace using google spreadsheet. Moreover, I'm trying to come up with a script that would send me an email when a certain product reaches a value below 2 so that I would know that a certain product needs to be restock. I'm do not know the basics of coding, but here's what I got so far:
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var ProductA = sheet.getRange("B2").getValue();
var Product B = sheet.getRange("B3").getValue();
var min = 2
if (ProductA<min) MailApp.sendEmail('n********#googlegroups.com', 'LOW REAGENT STOCK', 'Attention! Your stock of ProductA is running low. Please proceed to restock.');
if (ProductB<min) MailApp.sendEmail('n********#googlegroups.com', 'LOW REAGENT STOCK', 'Attention! Your stock of ProductB is running low. Please proceed to restock.');
}
I put the trigger on onEdit to run the script and I intent to expand the list with more products. The thing is that if one product as already reached a value below 2 and if a change another one, the script will send email for both of them. With more products, this becomes a nuisance, because I would received a bunch of emails if other values remain below 2. Can someone help me out with this? I couldn't find any solution to this so far and I would truly appreciate some help.
Thank you!
When the "onEdit" trigger fires, it receives the event object as parameter containing some useful information about the context, in which the edit action occurred.
For example,
function onEdit(e) {
// range that was edited
var range = e.range;
//value prior to the edit action
var oldValue = e.oldValue;
//new value
var value = e.value;
//sheet the action came from
var sheet = range.getSheet();
//cell coordinates (if edited range is a single cell)
//or the upper left boundary of the edited range
var row = range.getRow();
var col = range.getColumn();
}
You can inspect the event object to get the cell that was edited and see if it's in column B.
var productsColIndex = 1; //column A index;
var inventoryColIndex = 2; //column B index
var range = e.range;
var value = e.value;
var sheet = range.getSheet();
var editedRow = range.getRow();
var editedCol = range.getColumn();
var productName = sheet.getRange(editedRow, productsColIndex).getValue();
//checking if
//1) column B was edited
//2) the product exists in column A
//3) new value is less than 2
if ((editedCol == inventoryColIndex) && productName && value < 2) {
//code for sending notification email.
}
Finally, because simple triggers like onEdit() can't call services that require authorization, it's better to create a function with a different name and then set up the installable trigger manually. In your Script Editor, go to "Edit" -> "Current project's triggers" -> "Add a new trigger" , select your function name from the dropdown list, and pick the following options: "From spreadsheet", "On edit".

How to remove duplicate data from child object called in entity framework?

var eventDetails = (from e in db.tb_Event
select new
{
e.EventID,
e.tb_Customer.CustomerName,
e.StartDate,
e.EndDate,
loc = (from l in db.tb_EventLocation where l.EventID == e.EventID select new { l.tb_Location.LocationName }).Distinct(),
e.Objective
});
This is the correct way do do it. Try this out, this is working fine for me. Since you cannot use Include() for filtering you have to use projection technique.

Apex - Salesforce.com - I need help writing an APEX class to test my working trigger - Chatter - Monitor specific keywords

Here is my working trigger
trigger CheckChatterPostsOnNSP on FeedItem (before insert) {
Set<Id> nspIds = new Set<Id>();
//Get the NSP that will be updated
List<Non_Standard_Pricing__c> nsp2Update = new List<Non_Standard_Pricing__c>();
//Get the key prefix for the NSP object via a describe call.
String nspKeyPrefix = Non_Standard_Pricing__c.sObjectType.getDescribe().getKeyPrefix();
//Get the Id of the user
Id profileId = UserInfo.getProfileId();
for (FeedItem f: trigger.new) {
String parentId = f.parentId;
if(profileId == '00e30000000eWXR') {// Users profile must be Sales and Service
//We compare the start of the 'parentID' field to the NSP key prefix to
//restrict the trigger to act on posts made to the NSP object.
if (
parentId.startsWith(nspKeyPrefix) &&
(
f.Body.contains('***APPROVED BY CHANNEL***') ||
f.Body.contains('***APPROVED BY CSM***') ||
f.Body.contains('[APPROVED BY CHANNEL]') ||
f.Body.contains('[APPROVED BY CSM]')
)
){
nspIds.add(f.parentId);
}
}
}
List < Non_Standard_Pricing__c > nsps = [select id, Pre_Approved_Service_Discount__c, ownerId
from Non_Standard_Pricing__c where id in :nspIds];
for (Non_Standard_Pricing__c n: nsps) {
//We compare the creator of the Chatter post to the NSP Owner to ensure
//that only authorized users can close the NSP using the special Chatter 'hot-key'
n.Pre_Approved_Service_Discount__c = true;
nsp2Update.add(n);
}
update nsp2Update;
}
Here is my attempt to write an APEX Test Class
#isTest
public class CheckChatterPostsOnNSPTEST {
static testMethod void CheckChatterPostsOnNSPTEST() {
//Create and insert opp
Opportunity opp = new Opportunity(Name='test opp', StageName='stage', Probability = 95, CloseDate=system.today());
insert opp;
//Create and insert NSP
Non_Standard_Pricing__c NSP = new Non_Standard_Pricing__c(Opportunity__c = opp.Id, Status__c = 'Open');
insert NSP;
//Find user with Profile = Sales and Service
Profile SalesNService = [Select id from Profile where Name = 'Sales and Service' limit 1];
User u = new User(
Alias = 'standt',
Email='standarduser#testorg.com',
EmailEncodingKey='UTF-8',
LastName='Testing',
LanguageLocaleKey='en_US',
LocaleSidKey='en_US',
ProfileId = SalesNService.Id,
TimeZoneSidKey='America/Los_Angeles',
UserName='standarduser#testorg.com'
);
System.runAs(u)
{
//Create FeedItem entry with text '[APPROVED BY CHANNEL]'
FeedItem post = new FeedItem();
post.body = '[APPROVED BY CHANNEL]';
//Now update the opportunites to invoke the trigger
Test.startTest();
insert post;
Test.stopTest();
}
//Assertion Testing
for(Opportunity o : [select Id, Name, Primary_NSP__r.Pre_Approved_Service_Discount__c from Opportunity where Id = :opp.Id]){
system.assert(o.Primary_NSP__r.Pre_Approved_Service_Discount__c = true);
}
}
}
I'm getting the following errors
Message: System.QueryException: List has no rows for assignment to SObject
Stack Trace: Class.CheckChatterPostsOnNSPTEST.CheckChatterPostsOnNSPTEST: line 14, column 1
Any help is greatly appreciated.
That'd be pointing to this line:
Profile SalesNService = [Select id from Profile where Name = 'Sales and Service' limit 1];
Simply check if this query returns something? Typo in the profile name (maybe you have them with underscores or "Sales & Service")? Maybe there's no such profile in org at all (for example if you've created such one on production but the sandbox you're in was not refreshed afterwards)?
I'm afraid we can't help you more than that ;) It can't be even related to API versions, "seeAllData" etc because docs say Profiles are still visible.