从Meteor中的数组中取出一个条目。

9

我在我的Meteor 1.1.0.2应用程序中有以下(简化的)SimpleSchema模式:

Tickers.attachSchema(
    new SimpleSchema({
        entries: {
            type: [TickerEntries],
            defaultValue: [],
            optional: true
        }
    })
);

TickerEntries = new SimpleSchema({
    id: {
        type: String,
        autoform: {
            type: "hidden",
            label: false,
            readonly: true
        },
        optional: true,
        autoValue: function () {
            if (!this.isSet) {
                return new Mongo.Collection.ObjectID()._str;
            }
        }
    },
    text: {
        type: String,
        label: 'Text'
    }
};

我在数据库中有以下条目:

{
    "_id" : "ZcEvq9viGQ3uQ3QnT",
    "entries" : [
        {
            "text" : "a",
            "id" : "fc29774dadd7b37ee0dc5e3e"
        },
        {
            "text" : "b",
            "id" : "8171c4dbcc71052a8c6a38fb"
        }
    ]
}

我希望删除指定ID的entries数组中的一个条目。

如果我在meteor-mongodb-shell中执行以下命令,它将可以顺利工作:

db.Tickers.update({_id:"3TKgHKkGnzgfwqYHY"}, {"$pull":{"entries": {"id":"8171c4dbcc71052a8c6a38fb"}}})

但问题是,如果我在Meteor内部执行同样的操作,它就不起作用。这是我的代码:
Tickers.update({id: '3TKgHKkGnzgfwqYHY'}, {$pull: {'entries': {'id': '8171c4dbcc71052a8c6a38fb'}}});

我还尝试了以下方法:

Tickers.update('3TKgHKkGnzgfwqYHY', {$pull: {'entries': {'id': '8171c4dbcc71052a8c6a38fb'}}});

这些命令都没有报错,但它们并没有从我的文档中删除任何内容。

可能是$pull命令没有得到正确支持,或者我犯了错误?

谢谢提前!

编辑: 我找到了问题,但在我的描述中看不到它,因为我简化了架构。在我的应用程序中,TickerEntries有一个额外的属性timestamp

TickerEntries = new SimpleSchema({
    id: {
        type: String,
        optional: true,
        autoValue: function () {
            if (!this.isSet) {
                return new Mongo.Collection.ObjectID()._str;
            }
        }
    },
    timestamp: {
        type: Date,
        label: 'Minute',
        optional: true,
        autoValue: function () {
            if (!this.isSet) { // this check here is necessary!
                return new Date();
            }
        }
    },
    text: {
        type: String,
        label: 'Text'
    }
});

感谢Kyll的提示,我创建了一个Meteorpad,并发现autovalue函数是导致问题的原因。

我现在已经将该函数更改为以下代码:

autoValue: function () {
    if (!this.isSet && this.operator !== "$pull") { // this check here is necessary!
        return new Date();
    }
}

现在已经可以工作了。似乎在拉取项目/对象时返回自动值时,它会取消拉取操作,因为该值未设置为返回的值(因此时间戳属性保留旧值但未被拉取)。
这是相应的Meteorpad测试(只需注释掉autovalue函数中的运算符检查即可):http://meteorpad.com/pad/LLC3qeph66pAEFsrB/Leaderboard 感谢您所有人的帮助,您所有的帖子对我非常有帮助!

1
我建议您起草一个MeteorPad来展示您的问题(创建数据库,添加模式,填充数据,尝试删除并显示失败)。另一个要点:删除附加的模式是否对您的问题有任何影响?如果没有,您可能希望将它们从问题中完全删除,因为现在我真的不知道这些模式是否重要。最后,恭喜您的帖子格式和清晰度!如果您在问题中添加[javascript]标签,它将自动为代码添加颜色。 - Kyll
1
我建议您可能犯了一个错误,或者在某个地方存在配置错误或冲突。我已经提交了一个完全工作的案例作为答案。如果其他因素干扰了 $pull 的预期行为,它应该有助于缩小您可能遇到的任何问题。 - Blakes Seven
1
解决了我们的问题 - autovalue 阻止了 $pull。感谢 @reini122 的详尽问答。 - Jason Lunsford
只是为了澄清一下:我遇到了完全相同的问题,但我还必须在“id”的“autovalue”上添加“if(!this.isSet && this.operator!==”$pull“)”,以使一切正常工作。干得好,找出来了! - guillim
2个回答

5
对于一个基本的Meteor应用程序,我对此表示怀疑。如果您创建一个全新的项目并仅定义集合,则$pull运算符将按预期工作: 控制台:
meteor create tickets
cd tickets
meteor run

然后打开 Shell 并插入您的数据:
meteor mongo

> db.tickets.insert(data)   // exactly your data in the question

然后只需生成一些基本的代码和模板:

tickers.js

Tickers = new Meteor.Collection("tickers");

if (Meteor.isClient) {

  Template.body.helpers({
    "tickers": function() {
      return Tickers.find({});
    }
  });

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

tickers.html

<head>
  <title>tickers</title>
</head>

<body>
  <h1>Welcome to Meteor!</h1>

  <ul>
    {{#each tickers}}
      {{> ticker}}
    {{/each}}
  </ul>

</body>

<template name="ticker">
  <li>
    {{_id}}
    <ul>
      {{#each entries}}
        {{> entry }}
      {{/each}}
    </ul>
  </li>
</template>

<template name="entry">
  <li>{{ id }} - {{text}}</li>
</template>

应用程序应该正常运行,所以在您的浏览器控制台中执行 .update() 命令(为了便于阅读进行缩进):
Tickers.update(
    { "_id": "ZcEvq9viGQ3uQ3QnT" },
    { "$pull": { "entries": { "id": "fc29774dadd7b37ee0dc5e3e" } }}
)

该项已从条目中删除,页面刷新后该项将不再显示。所有的东西都消失了,正如我们所期望的那样。

即使添加SimpleSchemaCollection2包,在这里也没有任何区别:

 meteor add aldeed:simple-schema
 meteor add aldeed:collection2

tickers.js

Tickers = new Meteor.Collection("tickers");

TickerEntries = new SimpleSchema({
  "id": {
    type: String,
    optional: true,
    autoValue: function() {
      if (!this.isSet) {
        return new Mongo.Collection.ObjectID()._str
      }
    }
  },
  "text": {
    type: String
  }
});

Tickers.attachSchema(
  new SimpleSchema({
    entries: { type: [TickerEntries] }
  })
);


if (Meteor.isClient) {

  Template.body.helpers({
    "tickers": function() {
      return Tickers.find({});
    }
  });

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

重新初始化数据并在浏览器控制台中运行相同的命令,一切都保持不变。
检查自己的操作或其他差异中的任何打字错误,以了解为什么这对您无效。
我强烈建议这样做,因为像这样“重新开始”显示了预期的行为,如果您看到不同的行为,则很可能是您安装的另一个插件存在问题。
但通常情况下,这有效。

谢谢你提供这个干净而详尽的示例!:-) - reini122
@reini122 我真的希望这里有些东西可以“解决”问题,但如果没有,我的意图是展示我从你的问题中能够推断出的基本软件包的响应情况。如果您发现任何冲突,请随时通知我进行错误报告。StackOverflow的评论稍后可以清理,但如果存在软件包冲突导致问题出现,则我个人会有兴趣进行干预以解决问题。 - Blakes Seven
是的,我已经解决了我的问题,并在原始问题中编辑了解决方案。希望这很清楚。我还添加了一个Meteorpad来模拟这个问题,但这明确是SimpleSchema的问题,因为自动值会阻止拉取操作符在时间戳字段的情况下工作,但在ID字段中的类似代码并不会破坏功能。 - reini122
reini122,实际上对我来说,在子模式的id上使用autoValue也破坏了$pull功能。但是通过你的解决方法已经修复了 :) - Dan

0

顺便提一下,如果有其他人在寻找答案。

如果您正在使用SimpleSchema,则有两个选项: 数组字段应标记为可选

arr: {
 type:Array,
 optional:true
}

或者在更新查询中使用getAutoValues: false

Coll.update({}, {$pull: {arr: ''}}, {getAutoValues: false});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接