#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 и т. Д.