Как да създадете нов възел само ако възелът не съществува в neo4j

Използвам neo4j и vertx.

Използвам neo4j-jdbc.

Успях да създам потребител, но как мога да „надстроя“ тази заявка, за да създам нови потребители (с уникален индекс), само ако този потребител не съществува. UserId трябва да бъде първичният ключ.

 private final Logger logger = Logger.getLogger(Neo4jRepo.class);
    private Connection conn = null;

    public Neo4jRepo() {
        logger.debug("Neo4jRepo, Init");
        try {
            Class.forName("org.neo4j.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:neo4j://localhost:7474/");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);

        }
    }
..
public boolean addDistanceUserListByForUserId(String userId) {
        try {
            final PreparedStatement ps = conn.prepareStatement( "create (n:User {name:{1}})" );
            ps.setString( 1, "userId" );
            ps.execute();

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

Благодаря ти, Рей.


person rayman    schedule 17.09.2015    source източник
comment
Ако използвате neo4J като локален хост, трябва да следите за вградени neo4j, много по-добри характеристики.   -  person Supamiu    schedule 17.09.2015
comment
neo4j ще бъде като външна услуга. Мислехме да го вградим. но след това губим GUI и други неща. мислите ли, че embedded е по-добър от ext?   -  person rayman    schedule 17.09.2015
comment
Embedded е по-добре, ако сте на същия сървър :) GUI може да бъде извлечен с помощта на embedded :)   -  person Supamiu    schedule 17.09.2015
comment
в случай, че правя дистанционно Как мога всъщност да получа Node по Id с помощта на jdbc конектора? някаква идея как да го картографирам?   -  person rayman    schedule 17.09.2015
comment
Никога не използвайте nodeId като данни, трябва да добавите свой собствен идентификационен номер и да го зададете уникален, като използвате ограничения. В противен случай можете да извлечете възел чрез неговия идентификатор с cypher (start n=node(‹id›))   -  person Supamiu    schedule 17.09.2015
comment
Не го използвам като данни.. да кажем, че искам да знам дали възелът (по неговия идентификатор) вече е там и в случай че е... как да извлека самия възел при същата транзакция? може ли MERGE да ми върне възела, в случай че вече съществува?   -  person rayman    schedule 17.09.2015


Отговори (2)


Използвайте MERGE вместо CREATE:

"MERGE (n:User {name:{1}})"

[АКТУАЛИЗАЦИЯ 1]

Следното е пример за това как да модифицирате addDistanceUserListByForUserId(), така че да връща Map<String, Object>, съдържащ свойствата на създадения/съществуващ User.

public Map<String, Object> addDistanceUserListByForUserId(String userId) {
    try {
        final PreparedStatement ps = conn.prepareStatement(
            "MERGE (n:User {name:{1}}) RETURN n" );
        ps.setString( 1, "userId" );
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            return (Map<String, Object>) rs.getObject("n");
        }
    } catch (SQLException e) { 
        throw new RuntimeException(e);
    } 
    return null; 
}

[АКТУАЛИЗАЦИЯ 2]

Във вашия конкретен случай, тъй като имате ограничение за уникалност на :User(name) и съществуващите User възли могат да имат свойства, различни от name -- простата заявка MERGE (n:User {name:{1}}) може да причини ConstraintViolation грешка, ако съществува съществуващ User със същия name, но има и други свойства.

За да заобиколите това, опитайте да замените оператора MERGE с тази по-сложна заявка:

OPTIONAL MATCH (n:User { name:{1} })
WITH (CASE WHEN n IS NULL THEN [1] ELSE [] END ) AS todo
FOREACH (x IN todo | CREATE (:User { name:{1} }))
WITH todo
MATCH (n:User { name:{1} })
RETURN n;

Ето обяснение на това запитване:

  • Той използва OPTIONAL MATCH, така че ако User с посочения name не бъде намерен, останалата част от заявката не се пропуска (но n ще бъде NULL).
  • След това създава колекция todo, която ще каже на клаузата FOREACH дали трябва да създаде новия възел User. Клаузата FOREACH не прави нищо, ако колекцията todo е празна.
  • Трябва да има WITH клауза между модифицираща клауза (като FOREACH) и последваща MATCH клауза. Всъщност не е нужно да предаваме нищо напред, така че просто използваме todo, тъй като вече го имаме под ръка.
  • Имаме нужда от друга MATCH заявка, защото искаме да върнем възела, който или е намерен, или който току-що сме създали. Но няма начин да получим възела, който е създаден от FOREACH, освен ако не направим друг MATCH.
person cybersam    schedule 17.09.2015
comment
Вижте актуализирания ми отговор. Не съм тествал този код, но изглежда, че трябва да работи. - person cybersam; 18.09.2015
comment
Това работи, но използвам уникални ограничения за името и имам друго свойство, наречено възраст. така че в случай, че потребителят вече съществува с име, но има разлика в възрастта и аз се опитвам да обединя, получавам това изключение: Грешка при изпълнение на cypher statement(s) [{code=Neo.ClientError.Schema.ConstraintViolation, message=Node 15 вече съществува с етикет Име на потребител и свойство=[Jossef]}] - person rayman; 18.09.2015
comment
Актуализирах отговора си с предложение, за да можете да заобиколите проблема с ConstraintViolation`. - person cybersam; 18.09.2015

Трябва да използвате MERGE вместо CREATE. Това ще създаде възел, ако не съществува. Ако възелът вече съществува - тогава MERGE ще действа като нормална MATCH операция.

Важно: трябва да използвате само свойства с уникално ограничение в синтаксиса на {} свойства. Neo4j ще обедини възли, които имат същите свойства в {}.

Ако имате допълнителни данни за задаване на възел след сливане, тогава:

MERGE (user:User {name: "John", age: 20}) - ГРЕШЕН начин. Тъй като в базата данни няма възел с такава комбинация от свойства name и age и базата данни ще се опита да създаде този възел. И това ще доведе до ConstraintViolation, защото такова name вече съществува.

Правилна версия:

MERGE (user:User {name: "John"}) 
SET user.age = 20

Тази версия първо ще търси възел (и ще създаде, ако е необходимо) и едва след това ще зададе свойството на този възел.

person FylmTM    schedule 18.09.2015