Как правильно использовать IF THEN в AQL?

Я пытаюсь использовать AQL в стиле IF THEN, но единственным соответствующим оператором, который я смог найти в документации по AQL, был троичный оператор. Я пытался добавить синтаксис IF THEN к моему уже работающему AQL, но он выдает синтаксические ошибки независимо от того, что я пытаюсь сделать.

LET doc = DOCUMENT('xp/a-b')
LET now = DATE_NOW()
doc == null || now - doc.last >= 45e3 ? 
  LET mult = (doc == null || now - doc.last >= 6e5 ? 1 : doc.multiplier)
  LET gained = FLOOR((RAND() * 3 + 3) * mult)
  UPSERT {_key: 'a-b'}
  INSERT {
    amount: gained,
    total: gained,
    multiplier: 1.1,
    last: now
  }
  UPDATE {
    amount: doc.amount + gained,
    total: doc.total + gained,
    multiplier: (mult < 4 ? FLOOR((mult + 0.1) * 10) / 10 : 4),
    last: now
  }
  IN xp
  RETURN NEW
 : 
  RETURN null

Выдает следующее сообщение об ошибке:

stacktrace: ArangoError: AQL: syntax error, unexpected identifier near 'doc == null || now - doc.last >=...' at position 1:51 (while parsing)

1 ответ

Решение

Тернарный оператор не может использоваться как конструкция if/else так, как пытался. Это для условных (под) выражений, которые вы используете для вычисления mult, Он не может стоять сам по себе, ничто не может быть возвращено или назначено, если вы напишите это как выражение if.

Более того, для этого потребуются фигурные скобки, но проблема в том, что тело содержит такие операции, как LET, UPSERT а также RETURN, Это языковые конструкции, которые нельзя использовать внутри выражений.

Если я правильно понимаю, вы хотите:

  • вставить новый документ, если нет документа с ключом a-b существует еще в коллекции xb
  • если он существует, то обновите его, но только если последнее обновление было 45 секунд или дольше назад

Работает ли у вас следующий запрос?

FOR id IN [ 'xp/a-b' ]
    LET doc = DOCUMENT(id)
    LET key = PARSE_IDENTIFIER(id).key
    LET now = DATE_NOW()
    FILTER doc == null || now - doc.last >= 45e3
    LET mult = (doc == null || now - doc.last >= 6e5 ? 1 : doc.multiplier)
    LET gained = FLOOR((RAND() * 3 + 3) * mult)
    UPSERT { _key: key }
    INSERT {
        _key: key,
        amount: gained,
        total: gained,
        multiplier: 1.1,
        last: now
    }
    UPDATE {
        amount: doc.amount + gained,
        total: doc.total + gained,
        multiplier: (mult < 4 ? FLOOR((mult + 0.1) * 10) / 10 : 4),
        last: now
    }
    IN xp
    RETURN NEW

я добавил _key в INSERTв противном случае документ получит автоматически сгенерированный ключ, который, по-видимому, не предназначен. Используя FOR петля и FILTER действует как конструкция IF (без ELSE). Поскольку это запрос на изменение данных, нет необходимости явно RETURN что-нибудь и в исходном запросе вы RETURN null в любом случае. В то время как ваш приведет к [ null ]Мое производит [ ] (действительно пустой результат), если вы попытаетесь выполнить запрос в быстрой последовательности и ничего не будет обновлено или вставлено.

Обратите внимание, что необходимо использовать PARSE_IDENTIFIER() получить ключ из строки идентификатора документа и сделать INSERT { _key: key }, С INSERT { _key: doc._key } вы столкнетесь с ошибкой неверного ключа документа в случае вставки, потому что если нет документа xp/a-b, DOCUMENT() возвращается null а также doc._key поэтому также null, что приводит к _key: null - который является недействительным.

Другие вопросы по тегам