文档更新 #

一、更新概述 #

ArangoDB提供多种更新文档的方式,包括部分更新(UPDATE)和完全替换(REPLACE)。

1.1 更新方式对比 #

方式 说明 保留未指定字段
UPDATE 部分更新
REPLACE 完全替换

1.2 文档版本 #

每次更新都会生成新的 _rev

json
{
    "_key": "user_001",
    "_rev": "_abc124",
    "name": "张三"
}

二、UPDATE更新 #

2.1 基本UPDATE #

aql
UPDATE "user_001" WITH {
    age: 29,
    city: "上海"
} IN users

2.2 使用_key更新 #

aql
UPDATE { _key: "user_001" } WITH {
    age: 29
} IN users

2.3 使用_id更新 #

aql
UPDATE "users/user_001" WITH {
    age: 29
} IN users

2.4 条件更新 #

aql
FOR user IN users
    FILTER user.age < 18
    UPDATE user WITH {
        status: "minor"
    } IN users

2.5 返回更新后的文档 #

aql
UPDATE "user_001" WITH {
    age: 29
} IN users
RETURN NEW

2.6 返回更新前的文档 #

aql
UPDATE "user_001" WITH {
    age: 29
} IN users
RETURN OLD

2.7 返回新旧文档对比 #

aql
UPDATE "user_001" WITH {
    age: 29
} IN users
RETURN {
    old: OLD.age,
    new: NEW.age
}

三、REPLACE替换 #

3.1 基本REPLACE #

aql
REPLACE "user_001" WITH {
    name: "张三",
    email: "zhangsan@example.com",
    city: "上海"
} IN users

3.2 条件替换 #

aql
FOR user IN users
    FILTER user.status == "inactive"
    REPLACE user WITH {
        name: user.name,
        email: user.email,
        status: "deleted",
        deletedAt: DATE_NOW()
    } IN users

3.3 REPLACE vs UPDATE #

aql
UPDATE "user_001" WITH { age: 30 } IN users

REPLACE "user_001" WITH { name: "张三", age: 30 } IN users

四、批量更新 #

4.1 批量更新所有文档 #

aql
FOR user IN users
    UPDATE user WITH {
        updatedAt: DATE_NOW()
    } IN users

4.2 条件批量更新 #

aql
FOR user IN users
    FILTER user.city == "北京"
    UPDATE user WITH {
        region: "华北"
    } IN users

4.3 批量更新并返回 #

aql
FOR user IN users
    FILTER user.status == "pending"
    UPDATE user WITH {
        status: "active"
    } IN users
RETURN NEW

4.4 使用表达式更新 #

aql
FOR user IN users
    UPDATE user WITH {
        age: user.age + 1,
        updatedAt: DATE_NOW()
    } IN users

五、原子更新 #

5.1 数值增减 #

aql
UPDATE "product_001" WITH {
    stock: OLD.stock - 1,
    sales: OLD.sales + 1
} IN products

5.2 使用OLD引用 #

aql
UPDATE "user_001" WITH {
    loginCount: OLD.loginCount + 1,
    lastLogin: DATE_NOW()
} IN users

5.3 数组操作 #

添加到数组:

aql
UPDATE "user_001" WITH {
    hobbies: PUSH(OLD.hobbies, "摄影")
} IN users

从数组移除:

aql
UPDATE "user_001" WITH {
    hobbies: REMOVE_VALUE(OLD.hobbies, "游泳")
} IN users

5.4 对象合并 #

aql
UPDATE "user_001" WITH {
    address: MERGE(OLD.address, { city: "上海" })
} IN users

六、更新选项 #

6.1 waitForSync #

aql
UPDATE "user_001" WITH {
    age: 29
} IN users
OPTIONS { waitForSync: true }

6.2 keepNull #

保留null值:

aql
UPDATE "user_001" WITH {
    middleName: null
} IN users
OPTIONS { keepNull: true }

删除字段(keepNull: false):

aql
UPDATE "user_001" WITH {
    middleName: null
} IN users
OPTIONS { keepNull: false }

6.3 mergeObjects #

合并嵌套对象:

aql
UPDATE "user_001" WITH {
    address: { city: "上海" }
} IN users
OPTIONS { mergeObjects: true }

6.4 ignoreRevs #

忽略版本检查:

aql
UPDATE "user_001" WITH {
    age: 29
} IN users
OPTIONS { ignoreRevs: true }

6.5 完整选项示例 #

aql
UPDATE "user_001" WITH {
    age: 29,
    city: "上海"
} IN users
OPTIONS {
    waitForSync: true,
    keepNull: false,
    mergeObjects: true
}
RETURN NEW

七、乐观锁 #

7.1 使用_rev检查 #

aql
UPDATE {
    _key: "user_001",
    _rev: "_abc123"
} WITH {
    age: 29
} IN users

7.2 条件更新 #

aql
LET doc = DOCUMENT("users/user_001")
UPDATE doc WITH {
    age: 29
} IN users
FILTER doc._rev == @expectedRev

7.3 JavaScript实现 #

javascript
var doc = db.users.document("user_001");
try {
    db.users.update({
        _key: doc._key,
        _rev: doc._rev,
        age: 29
    });
} catch (e) {
    if (e.errorNum === 1200) {
        print("文档已被其他操作修改");
    }
}

八、更新边文档 #

8.1 更新边属性 #

aql
UPDATE "follow_001" WITH {
    type: "friend",
    updatedAt: DATE_NOW()
} IN follows

8.2 批量更新边 #

aql
FOR edge IN follows
    FILTER edge.type == "follows"
    UPDATE edge WITH {
        type: "following"
    } IN follows

九、JavaScript API #

9.1 update方法 #

javascript
db.users.update("user_001", {
    age: 29,
    city: "上海"
});

9.2 updateByExample #

javascript
db.users.updateByExample(
    { city: "北京" },
    { region: "华北" }
);

9.3 replace方法 #

javascript
db.users.replace("user_001", {
    name: "张三",
    email: "zhangsan@example.com",
    city: "上海"
});

9.4 批量更新 #

javascript
db._query(`
    FOR user IN users
        FILTER user.status == "pending"
        UPDATE user WITH { status: "active" } IN users
`);

十、实战示例 #

10.1 更新用户状态 #

aql
UPDATE "user_001" WITH {
    status: "active",
    activatedAt: DATE_NOW(),
    updatedAt: DATE_NOW()
} IN users
RETURN NEW

10.2 增加计数器 #

aql
UPDATE "article_001" WITH {
    viewCount: OLD.viewCount + 1
} IN articles

10.3 添加标签 #

aql
UPDATE "article_001" WITH {
    tags: UNION_DISTINCT(OLD.tags, ["技术", "数据库"])
} IN articles

10.4 更新嵌套对象 #

aql
UPDATE "user_001" WITH {
    profile: MERGE(OLD.profile, {
        avatar: "https://example.com/new-avatar.jpg",
        bio: "更新后的简介"
    })
} IN users

10.5 库存扣减 #

aql
FOR order IN orders
    FILTER order._key == @orderKey
    FOR item IN order.items
        UPDATE item.productId WITH {
            stock: OLD.stock - item.quantity
        } IN products

10.6 批量更新状态 #

aql
FOR order IN orders
    FILTER order.status == "pending"
    AND order.createdAt < DATE_SUBTRACT(DATE_NOW(), 1, "day")
    UPDATE order WITH {
        status: "expired",
        expiredAt: DATE_NOW()
    } IN orders

十一、性能优化 #

11.1 使用索引 #

确保更新条件字段有索引:

javascript
db.users.ensureHashIndex(["status"]);

11.2 批量更新优化 #

aql
FOR user IN users
    FILTER user.status == "pending"
    LIMIT 1000
    UPDATE user WITH {
        status: "active"
    } IN users

11.3 避免全表更新 #

aql
FOR user IN users
    FILTER user._key IN @keys
    UPDATE user WITH {
        updatedAt: DATE_NOW()
    } IN users

十二、错误处理 #

12.1 文档不存在 #

aql
UPDATE "nonexistent_key" WITH {
    age: 29
} IN users
OPTIONS { ignoreErrors: true }

12.2 版本冲突 #

javascript
try {
    db.users.update({
        _key: "user_001",
        _rev: "old_rev",
        age: 29
    });
} catch (e) {
    if (e.errorNum === 1200) {
        print("版本冲突,请重试");
    }
}

12.3 Schema验证失败 #

javascript
try {
    db.users.update("user_001", {
        age: -1
    });
} catch (e) {
    print("验证失败: " + e.message);
}

十三、总结 #

文档更新要点:

  1. UPDATE:部分更新,保留未指定字段
  2. REPLACE:完全替换,删除未指定字段
  3. OLD引用:在更新中引用旧值
  4. 选项:keepNull、mergeObjects、waitForSync
  5. 乐观锁:使用_rev进行并发控制

下一步,让我们学习文档删除!

最后更新:2026-03-27