gpt4 book ai didi

javascript - 如何使用 Firebase 的 Firestore 在单个查询中执行 arrayUnion 和 arrayRemove?

转载 作者:行者123 更新时间:2023-12-01 15:22:39 28 4
gpt4 key购买 nike

我正在使用 firestore 更新我的对象上的数组。
我在 documentation 上找到了我可以执行数组联合和删除,这很棒,这是文档中给出的示例:

var washingtonRef = db.collection("cities").doc("DC");

// Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});

// Atomically remove a region from the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayRemove("east_coast")
});

如您所见,数据库有 2 个单独的查询,这使我的应用程序在数据库调用方面的成本增加了一倍,因此我想将它们分组到一个查询中,如下所示:
var washingtonRef = db.collection("cities").doc("DC");

washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia"),
regions: firebase.firestore.FieldValue.arrayRemove("east_coast")
});

不幸的是,这不起作用,只有最后一个命令被执行。

有没有办法让它工作?

最佳答案

介绍
编辑:这个答案最初是在现代模块化 SDK 发布之前编写的,它已经更新以涵盖这个新的 SDK 以及当时可用的旧命名空间 SDK。对于新项目,请使用模块化 SDK。
字段值对象
您的组合指令不起作用的原因(除了语法错误)是因为 FieldValue 对象的定义方式。
假设您在 update() 中定义了以下可供使用的对象。称呼:

// Firebase Namespaced SDK (v8 & older)
// import firebase as appropriate

const myArrayUnion = firebase.firestore.FieldValue.arrayUnion("greater_virginia")
const myArrayRemove = firebase.firestore.FieldValue.arrayRemove("east_coast")
// Firebase Modular SDK (v9+)
import { arrayUnion, arrayRemove } from "firebase/firestore";

const myArrayUnion = arrayUnion("greater_virginia")
const myArrayRemove = arrayRemove("east_coast")
返回的对象是 FieldValue 的实现。类和等价于
const myArrayUnion = {
_method: "FieldValue.arrayUnion",
_elements: ["greater_virginia"]
}

const myArrayRemove = {
_method: "FieldValue.arrayRemove",
_elements: ["east_coast"]
}
然后,基于 _method 的值,相应的字段转换指令为 serialised using this code并发送到 Firestore API。因为操作是根据 _method的值来切换的,只有 arrayUnion 之一或 arrayRemove可以在一条指令上进行。 arrayUnionarrayRemove两个 arrayUnionarrayRemove可以接受多个参数,将每个参数添加到内部 _elements数组如上所示。
因此添加两个 "value1""value2"同时到指定的字段,您将使用:
// Firebase Namespaced SDK (v8 & older)
firebase.firestore.FieldValue.arrayUnion("value1", "value2");
// Firebase Modular SDK (v9+)
arrayUnion("value1", "value2");
要将一组项目同时添加到指定字段,您可以使用:
// Firebase Namespaced SDK (v8 & older)
const addedElements = ["greater_virginia", "east_coast", "central"];

firebase.firestore.FieldValue.arrayUnion.apply(null, addedElements);
// or
firebase.firestore.FieldValue.arrayUnion(...addedElements);
// Firebase Modular SDK (v9+)
const addedElements = ["greater_virginia", "east_coast", "central"];

arrayUnion.apply(null, addedElements);
// or
arrayUnion(...addedElements);
选项
因此,您有三个选项,按易用性和推荐排序:
选项 1:批量写入
使用 batched write将允许您将指令一起写入数据库,如果任一部分失败,则不会更改任何内容。
// Firebase Namespaced SDK (v8 & older)
// import firebase as appropriate

var db = firebase.firestore();
var washingtonRef = db.collection("cities").doc("DC");
var batch = db.batch();

batch.update(washingtonRef, {regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")});
batch.update(washingtonRef, {regions: firebase.firestore.FieldValue.arrayRemove("east_coast")});

batch.commit()
.then(() => console.log('Success!'))
.catch(err => console.error('Failed!', err));
// Firebase Modular SDK (v9+)
import { getFirestore, arrayRemove, arrayUnion, doc, writeBatch } from "firebase/firestore";

const db = getFirestore();
const washingtonRef = doc(db, "cities", "DC");
const batch = writeBatch(db);

batch.update(washingtonRef, {regions: arrayUnion("greater_virginia")});
batch.update(washingtonRef, {regions: arrayRemove("east_coast")});

batch.commit()
.then(() => console.log('Success!'))
.catch(err => console.error('Failed!', err));
注:每个批处理写入最多可包含 500 次写入。
在最初编写此答案时(此后已被删除),每个转换指令( arrayUnionarrayRemoveincrementserverTimestamp )将计为 2 次操作到此限制,因为读取和写入都被计算在内这意味着一个批处理只能使用 250 个转换。
选项 2:反转数组
这种特殊的数据结构让人想起实时数据库和 arrayUnion 之前的数据结构。和 arrayRemove介绍了操作。
一般前提是在将数组上传到数据库之前对其进行转换。
const originalArr = ["greater_virginia", "east_coast", "central"]
被反转并存储为
const keyedObjectOfArr = {
"greater_virginia": 1
"east_coast": 1,
"central": 1
}
使用以下方法可以实现上述结果:
const keyedObjectOfArr = originalArr.reduce((acc, v) => (acc[v] = 1, acc), {});
并恢复正常使用
const originalArr = Object.keys(keyedObjectOfArr);
然后,当您想应用联合/删除时,您将使用以下内容:
// Firebase Namespaced SDK (v8 & older)
// import firebase as appropriate

/**
* Creates (or adds to the given object) changes to be committed to the database.
*
* Note: Add operations will override remove operations if they exist in both arrays.
*
* @param fieldPath The path to the 'array' field to modify
* @param addedArray (optional) Elements to be added to the field
* @param removedArray (optional) Elements to be removed from the field
* @param changes (optional) A previous changes object for chaining
*/
function addArrayChanges(fieldPath, addedArray = [], removedArray = [], changes = {}) {
var fvDelete = firebase.firestore.FieldValue.delete();
removedElements.forEach(e => changes[fieldPath + '.' + e] = fvDelete);
addedElements.forEach(e => changes[fieldPath + '.' + e] = 1);
return changes;
}

var washingtonRef = db.collection("cities").doc("DC");
var addedElements = ["greater_virginia"];
var removedElements = ["east_coast"];

var changes = addArrayChanges("regions", addedElements, removedElements);

washingtonRef.update(changes)
.then(() => console.log('Success!'))
.catch(err => console.error('Failed!', err));
// Firebase Modular SDK (v9+)
import { getFirestore, arrayRemove, arrayUnion, deleteField, doc, updateDoc, writeBatch } from "firebase/firestore";

/**
* Creates (or adds to the given object) changes to be committed to the database.
*
* Note: Add operations will override remove operations if they exist in both arrays.
*
* @param fieldPath The path to the 'array' field to modify
* @param addedArray (optional) Elements to be added to the field
* @param removedArray (optional) Elements to be removed from the field
* @param changes (optional) A previous changes object for chaining
*/
function addArrayChanges(fieldPath, addedArray = [], removedArray = [], changes = {}) {
const fvDelete = deleteField();
removedElements.forEach(e => changes[fieldPath + '.' + e] = fvDelete);
addedElements.forEach(e => changes[fieldPath + '.' + e] = 1);
return changes;
}

const db = getFirestore();
const washingtonRef = doc(db, "cities", "DC");
const addedElements = ["greater_virginia"];
const removedElements = ["east_coast"];

const changes = addArrayChanges("regions", addedElements, removedElements);

updateDoc(washingtonRef, changes)
.then(() => console.log('Success!'))
.catch(err => console.error('Failed!', err));
选项 3:交易
虽然此方法是一种选择,但对于此用例来说是不切实际的,建议不要使用。 This blog post涵盖了 Firebase 实时数据库中的数组,但这些问题也适用于大规模关注单个文档的内容。
请求功能
Firestore API 中可能有空间同时支持添加和删除数组条目,因为它们在序列化层是分开的。
interface FieldTransform {
fieldPath?: string;
setToServerValue?: FieldTransformSetToServerValue;
appendMissingElements?: ArrayValue;
removeAllFromArray?: ArrayValue;
increment?: Value;
}
所以您也可以提交 Feature Request看看会发生什么。

关于javascript - 如何使用 Firebase 的 Firestore 在单个查询中执行 arrayUnion 和 arrayRemove?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60923604/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com