我们使用这个云函数已经有一段时间了,我们使用如下所示的代码从单个FireStore文档中的一个唯一储物柜编号数组中为我们的用户提供一个单独的编号/代码.

function grabLocker(){
    return admin.firestore().runTransaction(async (t) => {              
        var lockerDoc = await t.get(lockerref);
        if(lockerDoc && lockerDoc.data()){
            var lockerArr = lockerDoc.data().lockers ? lockerDoc.data().lockers : [];                                       
            if (lockerArr.length > 0){
                var randomIndex = Math.floor(Math.random()*((lockerArr.length - 1)-0+1)+0);
                var newLockers = lockerArr.slice(0,randomIndex).concat(lockerArr.slice(randomIndex + 1));
                var userLocker = lockerArr.slice(randomIndex, randomIndex + 1);
                t.update(lockerref, {'lockers': newLockers});
                return {status: 'succes', locker: userLocker[0]};
            }
            return {status: 'empty'};
        }
        return {status: 'empty'};
    });
}

Screenshot of the firestore document

在我们最新的活动中,这个脚本给了600个请求储物柜的用户中的8个重复的号码.我们查了又查,但数组只有唯一的数字.

推荐答案

在可能的情况下,应避免使用传统array.根据您的问题,您似乎在lockers数组中至少有600个条目.每次在此事务中写入文档时,最终都必须移位数组中许多条目的索引.因此,对于每个声明的储物柜,您需要删除一个条目并移动至多599个其他条目.然后,Cloud FiRestore必须在服务器端协调这一点,而不会收到冲突的寄存柜请求.

这是低效的,并且可能会导致冲突,如本blog post on Arrays in Firebase中所讨论的.

最好的方法(无需重新设计数据库)是反转您的数组并使用值num(带‘.’替换为符合的‘-’)作 for each 条目的关键字.

{
  "lockers": {
    "28-001": {
      "beschikbaar": true,
      "code": "1694",
      "num": "28.001"
    },
    "28-002": {
      "beschikbaar": true,
      "code": "0957",
      "num": "28.002"
    },
    "28-003": {
      "beschikbaar": true,
      "code": "5192",
      "num": "28.003"
    },
    "28-004": {
      "beschikbaar": true,
      "code": "7830",
      "num": "28.004"
    }
  }
}

这意味着需要对grabLocker()进行编辑,以说明此更改.我们需要处理新 struct ,并使用FieldValue.delete()来移除现在认领的储物柜.使用这种 struct ,Cloud FiRestore可以比更新每个数组条目的索引更快地进行协调.

function grabLocker() {
  return admin.firestore().runTransaction(async (t) => {              
    const lockerDoc = await t.get(lockerref);
    const lockersObj = lockerDoc.get("lockers"); // lockerDoc always has a value, and `get(someField)` will return `undefined` if the document or the name field does not exist.
    const lockerKeyInfoArr = lockersObj ? Object.entries(lockersObj) : [];

    if (lockerKeyInfoArr.length === 0) {
      return {status: 'empty'};
    }

    const randomIndex = Math.floor(Math.random()*lockerKeyInfoArr.length);
    const [lockerKey, lockerInfo] = lockerKeyInfoArr[randomIndex];

    t.update(lockerref, {
      [`lockers.${lockerKey}`]: admin.firestore.FieldValue.delete() // deletes this entry
    });
    return {status: 'succes', locker: lockerInfo};
  });
}

Node.js相关问答推荐

如何使用updateMany()和Node.js的方法?

Mongoose:如何在文档中推送到Caped(有限大小,滚动窗口)数组?

Mongoose查询-如何根据当前查找ID获取其他集合并将其插入到当前查找中?

如何在JavaScript中使用Mongoose将项推送到MongoDB中的重嵌套数组

如何在Sequelize with Postgres中将m:n关联表ID从整数迁移到UUID?

Node.js 连接在查询完成之前终止

在 Nest 项目上运行 Jest 测试时,我的文件无法找到一个在测试之外没有任何问题的模块

suppress AWS SDK v2 弃用消息

级联定时器和Jest 的异步功能

Zod 模式中的self 数组

带有事件网格的 Azure 函数在没有 ngrok 的情况下在本地运行

如何promise AWS JavaScript 开发工具包?

如何在 node 调试器中禁用第一行中断

从 CoffeeScript 中的数组中删除一个值

在 Node.js 中的两个不同进程之间进行通信

node/express:使用 Forever 连续运行脚本时设置 NODE_ENV

使用 pg-promise 进行多行插入

Express.js中的bodyParser.urlencoded({extended: true }))和bodyParser.json()是什么意思?

使用 Node.js 我得到错误:EISDIR,读取

NodeJS:如何调试检测到 EventEmitter 内存泄漏.添加了 11 个侦听器