Как я могу использовать AQL с несколькими запросами, которые используют результат друг друга?

#graph #atomic #arangodb #aql #arangojs

#График #атомарный #arangodb #aql #arangojs

Вопрос:

У меня есть 2 вершины и ребро с именем user, device, ownership соответственно.

Моя бизнес-логика заключается в том, что когда я получаю информацию об устройстве, я обновляю ее с добавлением полей DateCreated и DateUpdated. Если я вставил это устройство, я вставляю нового пользователя со значениями по умолчанию и создаю к нему пограничное соединение. Если я обновляю, я просто возвращаю уже подключенного пользователя в результате. введите описание изображения здесь

Как я могу этого добиться, не теряя атомарности?

Я попробовал один запрос AQL, но без условий, похоже, это невозможно, и обход также не поддерживается операцией вставки / обновления.

Я могу выполнять отдельные запросы, но это теряет атомарность.

 var finalQuery = aql`
UPSERT ${deviceQuery} 
INSERT MERGE(${deviceQuery},{dateCreated:DATE_NOW()}) 
UPDATE MERGE(${deviceQuery},{dateUpdated:DATE_NOW()}) 
IN ${this.DeviceModel}
RETURN { doc: NEW, type: OLD ? 'update' : 'insert' }`;

var cursor = await db.query(finalQuery);
var result = await cursor.next();
if (result.type == 'insert') {
  console.log('Inserted documents')

  finalQuery = aql`
  LET user=(INSERT {
    "_key":UUID(),
      "name": "User"
    } INTO user
    RETURN NEW)
    
    INSERT {
    _from:${result.doc._id},
    _to:user[0]._id,
      "type": "belongs"
    }INTO ownership
    
    return user[0]`;

    cursor = await db.query(finalQuery);
    result = await cursor.next();
    console.log('New user:',result);
    
}
  

Комментарии:

1. Я сомневаюсь, что это может быть достигнуто. Вы будете продолжать сталкиваться access after data-modification с ошибками

Ответ №1:

Вы можете попробовать что-то вроде этого

 Upsert ....

FILTER !OLD
Let model = NEW

LET user= First(INSERT {
    "_key":UUID(),
      "name": "User"
    } INTO user
    RETURN NEW)
    
    INSERT {
    _from:model._id,
    _to:user._id,
      "type": "belongs"
    }INTO ownership
    
    return user
  

Комментарии:

1. Но это не возвращает пользователя, если происходит обновление. Для обоих сценариев (обновление и вставка) Мне нужен пользователь.

Ответ №2:

В итоге я разделяю запросы на модификацию и выбор.

 var finalQuery = aql`
LET device=(
UPSERT ${deviceQuery} 
INSERT MERGE(${deviceQuery},{dateCreated:DATE_NOW()}) 
UPDATE MERGE(${deviceQuery},{dateUpdated:DATE_NOW()}) 
IN ${this.DeviceModel}
RETURN { doc: NEW, type: OLD ? 'update' : 'insert' })
FILTER device[0].type=='insert'
LET user=(INSERT {
"_key":UUID(),
"name": "User"
} INTO user
RETURN NEW)

INSERT {
_from:device[0].doc._id,
_to:user[0]._id,
"type": "belongs"
}INTO ownership
return user[0]`;

var cursor = await db.query(finalQuery);
var result = await cursor.next();
if (result == null) {
  const deviceId=this.DeviceModel.name "/" queryParams._key;
  finalQuery = aql`
  FOR v,e,p IN 1..1 
  OUTBOUND ${deviceId} ownership 
  FILTER e.type=="belongs" 
  RETURN v `;

  cursor = await db.query(finalQuery);
  result = await cursor.next();
  isUpdate=true;
}
  

Таким образом, я обеспечиваю атомарность. Есть улучшения для управления, если cursor.extra.stats.writesExecuted true и т. Д.