Reputation: 4841
I have found that I can .save(objects)
which creates objects if the key doesn't exist. I have found that I can .bulkUpdate(objects)
which updates objects whose keys exist.
My question is: how do I do a bulk upsert? If the key exists, update it (merge), if it doesn't, create it.
Is there a way to do this without a lot of overhead?
Is it acceptable to do this?
db.collection("threads").bulkUpdate(keyedThreads);
db.collection("threads").save(keyedThreads);
Upvotes: 2
Views: 931
Reputation: 3696
This can be done with ArangoDB >= 3.7
and arangojs >= 7.5.0
https://arangodb.github.io/arangojs/latest/modules/collection.html#collectioninsertoptions
const db = new Database();
const collection = db.collection("some-collection");
const result = await collection.saveAll(
[
{ _key: "a", color: "blue", count: 1 },
{ _key: "b", color: "red", count: 2 },
],
{ overwriteMode: "update" }
);
Upvotes: 1
Reputation: 7632
@pluma (ArangoDB) wrote on 9 Jun 2017:
Upsert is only available via AQL. There is no collection.upsert method.
And @fceller (ArangoDB) added:
One of the major issues with upsert is that you access to old data. This can easily be handled in AQL, but not in a simple call to an upsert endpoint. Therefore we decided against such a call and instead implemented it in AQL.
Looks like there won't ever be a native implementation of collection.bulkUpsert
; however you can create your own helper function using AQL's UPSERT and MERGE functions.
TypeScript Example:
/**
* 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();
}
Source: collection.bulkUpsert.ts Gist
Upvotes: 2
Reputation: 711
REST Insert has the overwrite option. That is probably what you are looking for.
https://github.com/arangodb/arangojs/blob/master/src/collection.ts#L721
If not you need to use the AQL UPSERT.
Upvotes: 1