【问题标题】:How to ignore duplicate properties of other fields in the object?如何忽略对象中其他字段的重复属性?
【发布时间】:2016-03-27 06:15:06
【问题描述】:

我编写了一个 for 循环,它获取一个数据表并使用此架构创建 3,500 个对象:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var LocationSchema = new Schema({
  twp: {type: String, index: true, unique: true, dropDups: true},
  rge: {type: String, unique: true},
});


module.exports = mongoose.model('Location', LocationSchema);

假设这是第一个创建的对象:

{
    "_id" : ObjectId("56f5eb02683e79de61278449"),
    "rge" : "008W",
    "twp" : "004S",
    "__v" : 0
}

如果使用值twp: 004S 实例化任何其他对象,我希望仍然创建该对象,但没有 twp 值。它看起来像这样:

{
    "_id" : ObjectId("56f5eb02683e79de61274949"),
    "rge" : "009E",
    "__v" : 0
}

如您所见,我尝试添加 unique 和 dropDups,但这仍然创建了多个具有相同 twp 值的对象。我还尝试添加以下代码(根据某人的建议),但结果仍然相同。

var twpSet = new Set();

LocationSchema.methods.twp1 = function () {
    var curTwp = this.twp;

    if (twpSet.has(curTwp)) {
        this.twp = undefined; // remove the twp field once duplicated
    } else {
        twpSet.add(curTwp); // save the existing twp value
    }
};

LocationSchema.queue('twp1');

【问题讨论】:

标签: node.js mongodb mongoose mongodb-query


【解决方案1】:

问题在于,如果您未在文档中包含特定字段,但该字段上有一个 "unique" 索引,那么出于索引目的,该字段的值仍为 null

引用:

如果文档没有字段的值,则该项目的索引条目在包含它的任何索引中都将为空。因此,在许多情况下,您会希望将唯一约束与稀疏选项结合起来。稀疏索引跳过任何缺少索引字段的文档,而不是为索引条目存储 null。由于唯一索引不能有一个字段的重复值,如果没有 sparse 选项,MongoDB 将拒绝第二个文档以及所有没有索引字段的后续文档。

要解决这个问题,请在创建的索引上使用"sparse" 属性。下面是显示这两种情况的演示:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;


mongoose.set("debug",true);
mongoose.connect('mongodb://localhost/test');

var sparseSchema = new Schema({
  "a": { "type": String, "unique": true, "sparse": true },
  "b": { "type": String, "unique": true }
});

var Sparse = mongoose.model('Sparsetest',sparseSchema);


async.eachSeries(
  [{ "a": 1, "b": 2 },{ "a": 2 },{ "b": 3 },{ "b": 4 },{ "a": 3 }],
  function(item,callback) {
    Sparse.create(item,function(err,doc) {
      console.log(doc);
      callback(err);
    });
  },
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

代码注定会出错,但输出会告诉你发生了什么:

Mongoose: sparsetests.ensureIndex({ a: 1 }) { unique: true, sparse: true, background: true }
Mongoose: sparsetests.insert({ a: '1', b: '2', _id: ObjectId("56f706820c2db3902e557cff"), __v: 0 })
Mongoose: sparsetests.ensureIndex({ b: 1 }) { unique: true, background: true }
{ _id: 56f706820c2db3902e557cff, b: '2', a: '1', __v: 0 }
Mongoose: sparsetests.insert({ a: '2', _id: ObjectId("56f706820c2db3902e557d00"), __v: 0 })
{ _id: 56f706820c2db3902e557d00, a: '2', __v: 0 }
Mongoose: sparsetests.insert({ b: '3', _id: ObjectId("56f706820c2db3902e557d01"), __v: 0 })
{ _id: 56f706820c2db3902e557d01, b: '3', __v: 0 }
Mongoose: sparsetests.insert({ b: '4', _id: ObjectId("56f706820c2db3902e557d02"), __v: 0 })
{ _id: 56f706820c2db3902e557d02, b: '4', __v: 0 }
Mongoose: sparsetests.insert({ a: '3', _id: ObjectId("56f706820c2db3902e557d03"), __v: 0 })
undefined

                                  ^
MongoError: E11000 duplicate key error collection: test.sparsetests index: b_1 dup key: { : null }

所以对于创建的前四个文档来说一切都很好。第一个文档具有两个属性的唯一值,第二个不重复 "a",第三个和第四个不重复 "b"。值得注意的是,第三个和第四个文档不包含 "a" 属性,但由于该属性是 "sparse" 索引的,这不是问题。

"b" 属性并非如此,当我们尝试插入另一个文档时,该属性被视为null,该索引会引发重复键错误。尽管"a" 属性仍然是唯一的,但"b" 已经拥有null,所以它不是。

因此,如果您想要一个"unique" 索引但您不打算在每个 文档中包含该属性,则必须打开"sparse"

注意 "dropDups" 选项已被弃用,并且在 MongoDB 3.x 之后的任何版本中都是“无操作”。无论如何,从集合中删除现有的重复项从来都不是一个好的选择。如果您存在重复数据,则需要手动删除它。

【讨论】:

  • 所以为了实现这一点,我所要做的就是将sparse: true 添加到我的架构中?我试过了,但效果不太好。尝试谷歌以获取有关稀疏的更多信息。
  • @fresh5447 不仅有指向相关信息的超链接(和引文),而且还有一个工作示例向您展示出了什么问题。所以你不可能很努力。再次仔细阅读并查看您的代码哪里出错了。如果您希望它是unique,那么您从任何文档中“省略”它的字段都需要有sparse。否则就是重复的null
猜你喜欢
  • 2017-03-22
  • 1970-01-01
  • 2013-12-28
  • 2013-11-19
  • 2021-12-05
  • 2021-11-23
  • 2014-07-06
  • 2020-07-30
  • 2011-07-24
相关资源
最近更新 更多