Массовый апсерт в ArangoJS?

Я обнаружил, что могу .save(objects) создавать объекты, если ключ не существует. Я обнаружил, что могу .bulkUpdate(objects) обновлять объекты, ключи которых существуют.

У меня вопрос: как мне сделать массовый аперт? Если ключ существует, обновите его (объедините), если нет, создайте.

Есть ли способ сделать это без больших накладных расходов?

Допустимо ли это делать?

db.collection("threads").bulkUpdate(keyedThreads);
db.collection("threads").save(keyedThreads);

person Luke Pighetti    schedule 01.02.2019    source источник


Ответы (2)


@pluma (ArangoDB) написал 9 июня 2017 г .:

Upsert доступен только через AQL. Нет метода collection.upsert.

И @fceller (ArangoDB) добавил:

Одна из основных проблем с upsert - доступ к старым данным. Это может быть легко выполнено в AQL, но не в простом вызове конечной точки upsert. Поэтому мы отказались от такого вызова и вместо этого реализовали его на AQL.

Похоже, что нативной реализации collection.bulkUpsert никогда не будет; однако вы можете создать свою собственную вспомогательную функцию, используя UPSERT AQL и Функции MERGE.

TypeScript Пример:

/**
 * Upserts (merges) the content of the documents with the given documents and
 * optionally returns an array containing the documents’ metadata.
 *
 * @param {string|ArangoDB.Collection} collection - collection to use
 * @param {Document[]} documents - list of documents to upsert
 * @param opts? - optionally aggregate a result {inserted:number,updated:number}
 *  also see https://www.arangodb.com/docs/stable/aql/operations-upsert.html
 */
export async function bulkUpsert(
    collection: string | DocumentCollection,
    documents: Array<ArangoDB.DocumentData>,
    { aggregate, ...upsertOptions }: {
        ignoreRevs?: boolean,
        exclusive?: boolean,
        aggregate?: boolean
    } = {}
): Promise<{inserted:number,updated:number} | true>
{
    return await (
        await db.query({
            query:  'FOR doc IN @documents'
                  + ' UPSERT { _key: doc._key } INSERT doc UPDATE MERGE(OLD, doc)'
                  + ' IN '+(typeof collection === 'string' ? collection : collection.name)
                  + ' OPTIONS '+JSON.stringify(upsertOptions)
                  + (aggregate ?
                    ' COLLECT AGGREGATE inserted = SUM(OLD ? 0 : 1), updated = SUM(OLD ? 1 : 0)'
                  + ' RETURN {inserted,updated}' :
                    ' RETURN true'),
            bindVars: {documents}
        })
    ).next();
}

Источник: collection.bulkUpsert.ts Gist

person RienNeVaPlu͢s    schedule 03.11.2019

REST Insert имеет возможность перезаписи. Вероятно, это то, что вы ищете.

https://github.com/arangodb/arangojs/blob/master/src/collection.ts#L721

Если нет, вам нужно использовать AQL UPSERT.

person Jan Christoph Uhde    schedule 01.02.2019
comment
Поправьте меня, если я ошибаюсь, но разве это не заменит документы, а не объединит их? - person Luke Pighetti; 01.02.2019
comment
@LukePighetti, ты прав. Если вы не просто хотите синхронизировать данные из вашего приложения с базой данных, вам нужно будет написать запрос AQL, который использует инструкцию UPSERT. Нет никакого upsert REST / обработчика документов. - person Jan Christoph Uhde; 01.02.2019