如何更新嵌套对象子元素,其中某些条件 is/are 为真
How to update a nested object child element, where some condition(s) is/are true
注意:这不是重复问题,请阅读到最后并查看包含的图片。
我在 Firestore 中的 collection/document 中有一个嵌套对象和一个数组字段。
主要类别
- 饮料
- 零食
饮料项目是
- (水、能量、牛奶……)
零食是
- (薯片、饼干、玉米、..)
用户可以为具有到期日期的多个项目订阅两个类别:
- 饮料->能量
- 饮料->牛奶
- 零食->薯条
我想更新 [expDate] 字段,其中 [name] 等于 drinks 和 [type ] 等于 [能量]
我更重要地探索了 Firestore 文档 compound queries in Cloud Firestore 并阅读了很多关于 stackeoverflow 的文章和问题,但我找不到我的答案,下面是我的代码的一部分,我 tr.
db.collection(this.dbName)
.where("name", "==", "drinks")
.where("subscriptions.data.type", "==", "energy")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let data = doc.data();
if (data.email == email) {
let subscriptions = data.subscriptions;
subscriptions.forEach((subscription) => {
if (subscription.name == productName) {
let prodTypes = subscription.data;
prodTypes.forEach((prodType) => {
if (prodType.type == itemType) {
let docRef = fb.db.collection(this.dbName).doc(email);
fb.db
.collection(this.dbName)
.doc(email)
.update(docRef, {
subscriptions: [
{
data: [
{
expDate: expiration,
type: itemType,
},
],
name: productName,
},
],
});
}
});
}
});
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
我没有得到上述查询的任何控制台日志结果。
此查询无效:
db.collection(this.dbName)
.where("name", "==", "drinks")
.where("subscriptions.data.type", "==", "energy")
这 returns 个文件有:
- 字段
name
在其根部,值为 "drinks"
AND
- 有一个字段
type
嵌套在 data
下 nestedunder
subscriptions**under the root** with the value
"energy"`
您显示的文档中没有这些字段,因此查询不会 return 该文档。如果您在文档的根 下添加字段 ,您将看到查询 returns 它。
看起来您正在尝试 return 文档,其中 subscriptions
数组 的项目中包含 特定值。为此,您需要 use the array-contains
operator。此操作可以测试数组字段是否包含特定的 complete 值,例如:
db.collection(this.dbName)
.where("subscriptions", "array-contains", { ... })
但是这里你必须指定数组中必须存在的整个对象。如果该项目存在特定值,则无法检查 属性 是否存在,也无法检查嵌套数组,就像您在此处看到的那样。
与处理 NoSQL 数据库时通常的情况一样,解决方案是 change/augment 您的数据模型以允许用例。由于您要查询具有特定 name
和 type
的文档,请为该文档中存在的所有 names
和 types
添加顶级字段:
{
names: ["drinks", "snacks"],
types: ["energy", "water"]
subscriptions: [
...
]
}
现在您可以在查询中使用(其中一个)新的顶级字段:
db.collection(this.dbName)
.where("names", "array-contains", "drinks")
您不能添加第二个 array-contains
子句,因为一个查询在 Firestore 中只能有一个这样的子句。因此,在使用查询仅检索包含 drinks
.
的文档后,您必须过滤应用程序代码中的 types
根据我的理解,firebase 复合查询不适用于这种情况,我通过使用 javascript 映射帮助器更改对象并使用函数的 return 数据更新文档来解决问题(changeExpDate),如下:
changeExpDate(data, name, type, expDate) {
data = [data];
data.map((obj) => {
let subscriptions = obj.subscriptions;
for (var i = 0; i < subscriptions.length; i++) {
let items = obj.subscriptions[i].data;
for (var j = 0; j < items.length; j++) {
if (obj.subscriptions[i].name == name) {
if (items[j].type == type) {
obj.subscriptions[i].data[j].expDate = expDate;
}
}
}
}
});
return data;
}
结合你的情况,得到了以下代码:
let v = this.changeExpDate(
data, //The document objcet
productName, //Product Name
itemType, //Item type
expiration //Expiration date
);
try {
fb.db
.collection(this.dbName)
.doc(email)
.update(v[0])
.then(function () {
console.log("Updated!");
})
.catch(function (error) {
console.error("Error Updating: ", error);
});
} catch (error) {
console.error(error);
}
注意:这不是重复问题,请阅读到最后并查看包含的图片。
我在 Firestore 中的 collection/document 中有一个嵌套对象和一个数组字段。
主要类别
- 饮料
- 零食
饮料项目是
- (水、能量、牛奶……)
零食是
- (薯片、饼干、玉米、..)
用户可以为具有到期日期的多个项目订阅两个类别:
- 饮料->能量
- 饮料->牛奶
- 零食->薯条
我想更新 [expDate] 字段,其中 [name] 等于 drinks 和 [type ] 等于 [能量]
我更重要地探索了 Firestore 文档 compound queries in Cloud Firestore 并阅读了很多关于 stackeoverflow 的文章和问题,但我找不到我的答案,下面是我的代码的一部分,我 tr.
db.collection(this.dbName)
.where("name", "==", "drinks")
.where("subscriptions.data.type", "==", "energy")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let data = doc.data();
if (data.email == email) {
let subscriptions = data.subscriptions;
subscriptions.forEach((subscription) => {
if (subscription.name == productName) {
let prodTypes = subscription.data;
prodTypes.forEach((prodType) => {
if (prodType.type == itemType) {
let docRef = fb.db.collection(this.dbName).doc(email);
fb.db
.collection(this.dbName)
.doc(email)
.update(docRef, {
subscriptions: [
{
data: [
{
expDate: expiration,
type: itemType,
},
],
name: productName,
},
],
});
}
});
}
});
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
我没有得到上述查询的任何控制台日志结果。
此查询无效:
db.collection(this.dbName)
.where("name", "==", "drinks")
.where("subscriptions.data.type", "==", "energy")
这 returns 个文件有:
- 字段
name
在其根部,值为"drinks"
AND - 有一个字段
type
嵌套在data
下 nestedunder
subscriptions**under the root** with the value
"energy"`
您显示的文档中没有这些字段,因此查询不会 return 该文档。如果您在文档的根 下添加字段 ,您将看到查询 returns 它。
看起来您正在尝试 return 文档,其中 subscriptions
数组 的项目中包含 特定值。为此,您需要 use the array-contains
operator。此操作可以测试数组字段是否包含特定的 complete 值,例如:
db.collection(this.dbName)
.where("subscriptions", "array-contains", { ... })
但是这里你必须指定数组中必须存在的整个对象。如果该项目存在特定值,则无法检查 属性 是否存在,也无法检查嵌套数组,就像您在此处看到的那样。
与处理 NoSQL 数据库时通常的情况一样,解决方案是 change/augment 您的数据模型以允许用例。由于您要查询具有特定 name
和 type
的文档,请为该文档中存在的所有 names
和 types
添加顶级字段:
{
names: ["drinks", "snacks"],
types: ["energy", "water"]
subscriptions: [
...
]
}
现在您可以在查询中使用(其中一个)新的顶级字段:
db.collection(this.dbName)
.where("names", "array-contains", "drinks")
您不能添加第二个 array-contains
子句,因为一个查询在 Firestore 中只能有一个这样的子句。因此,在使用查询仅检索包含 drinks
.
types
根据我的理解,firebase 复合查询不适用于这种情况,我通过使用 javascript 映射帮助器更改对象并使用函数的 return 数据更新文档来解决问题(changeExpDate),如下:
changeExpDate(data, name, type, expDate) {
data = [data];
data.map((obj) => {
let subscriptions = obj.subscriptions;
for (var i = 0; i < subscriptions.length; i++) {
let items = obj.subscriptions[i].data;
for (var j = 0; j < items.length; j++) {
if (obj.subscriptions[i].name == name) {
if (items[j].type == type) {
obj.subscriptions[i].data[j].expDate = expDate;
}
}
}
}
});
return data;
}
结合你的情况,得到了以下代码:
let v = this.changeExpDate(
data, //The document objcet
productName, //Product Name
itemType, //Item type
expiration //Expiration date
);
try {
fb.db
.collection(this.dbName)
.doc(email)
.update(v[0])
.then(function () {
console.log("Updated!");
})
.catch(function (error) {
console.error("Error Updating: ", error);
});
} catch (error) {
console.error(error);
}