【问题标题】:Meteor collections: upsert w/ arrayMeteor 集合:带数组的 upsert
【发布时间】:2018-03-05 05:15:24
【问题描述】:

这个问题的形式已被问过几次,但我一直无法找到解决方案:

我有这样的架构(简化):

StatusObject = new SimpleSchema({
   statusArray: [statusSchema]
});

statusSchema 在哪里

{
    topicId:{
        type: String,
        optional: true
    },
    someInfo:{
        type: Number,
        optional: true,
        decimal: true
    },
    otherInfo:{
        type: Number,
        optional: true
    }
}

我正在尝试upsert - 使用以下流星方法代码:

var upsertResult = BasicInfo.update({
  userId: this.userId, 
  statusArray: {
    $elemMatch: { topicId : newStatus.topicId }
  }
}, { 
  $set: {
    "statusArray.$.topicId": newStatus.topicId,
    "statusArray.$.someInfo": newStatus.someInfo,
    "statusArray.$.otherInfo": newStatus.otherInfo
  }         
}, {
  multi: true,
  upsert: true
});

但我不断收到错误消息:statusArray must be an array 我想通过添加$,我确保它被识别为一个数组?我错过了什么?

【问题讨论】:

  • 您查询中的topicCompletion 字段是什么?你的意思是statusArray 吗?
  • 是的,抱歉 - 正在简化代码并错过了这一点。现在改变。
  • 好吧,现在使用$是合理的。虽然,你的意图还不清楚。您想将另一个对象添加到statusArray 数组中还是更新其中的现有对象?
  • 我想在数组中有一个 topicId=x 的对象。 (即 topicId 字段在所有数组元素中应该是唯一的)。然后我想更新该数组元素的 someInfo 和 otherInfo
  • 感谢您澄清这一点。最后一个问题:如果没有statusArray.topicId匹配newStatus.topicId的文档?创建新文档还是将新对象推送到 statusArray 数组中?

标签: meteor mongodb-query


【解决方案1】:

您的代码将 StatusArray 视为一个对象,

在进行 upsert 之前,先构建状态数组,假设您的当前值为 currentRecord

newStatusArray = currentRecord.statusArray
newStatusArray.push({
  topicId: newStatus.topicId,
  someInfo : newStatus.someInfo,
  otherInfo: newStatus.otherInfo
}) 

在 upsert 中,只需像这样引用它

$set: { statusArray: newStatusArray}

【讨论】:

  • 谢谢,但这需要我先拉出整个数组,然后将其重新保存到数据库中——这会变得非常低效吗?
  • 效率不是主要问题,因为无论如何它都必须检索数据。除非您在数组中有数千个元素,在这种情况下您的数据设计不正确。有可能更新单个元素,在这种情况下我想你会说$set: {"statusArray[x]": newValues}(其中 x 是你要更新的元素的索引)你可以试试
  • 我知道你从 mongo doco 那里得到了 $ 的东西。 MiniMongo 不支持完整的 Mongo 接口,所以 Meteor 基本上只提供了一个子集(甚至在服务器上)
  • 对,我明白了。我猜也不确定 Mongodb 本身的 upsert 功能。所以现在我基本上删除了包含 topicId 的数组元素,然后将它添加回数组中,如你所提到的......但仍然试图找出更多的 upsert 解决方案,如果可能的话,它只改变 1 个对象的 1 个字段数组 - 有很多用户,这对服务器造成负担。
【解决方案2】:

似乎(在您澄清 cmets 之后),您希望找到具有特定 userId 的文档并使用以下场景之一修改其 statusArray 数组:

  • 使用特定的topicId 值更新现有对象;
  • 如果数组没有具有特定topicId 值的对象,则添加一个新对象。

不幸的是,您不能仅使用一个数据库查询使其工作,所以它应该是这样的:

// try to update record
const updateResult = BasicInfo.update({
  userId: this.userId, 
  'statusArray.topicId': newStatus.topicId
}, { 
  $set: {
    "statusArray.$": newStatus
  }         
});

if (!updateResult) {
  // insert new record to array or create new document
  BasicInfo.update({
    userId: this.userId
  }, {
    $push: {
      statusArray: newStatus
    },
    $setOnInsert: {
      // other needed fields
    }
  }, {
    upsert: true
  });
}

【讨论】:

  • 谢谢!非常清晰和乐于助人。很抱歉延迟尝试此解决方案 - 已积压。
  • @ASX 别担心,我很高兴它帮助了你 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 2017-09-15
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 2018-10-27
相关资源
最近更新 更多