Mongo模式,具有唯一值的字符串数组

9
我正在创建一个Mongo文档的架构,我可以做到除了在非对象数组中防止重复项。我知道有addToSet,但我是指Mongo Schema。我不想使用$addToSet在更新时进行检查,而是希望它成为我的架构验证的一部分。下面是示例。
let sampleSchema = {
   name: { type: 'String', unique: true },
   tags: [{ type: 'String', unique: true }]
}

上面的代码片段可以防止name有重复的值。它允许将标签存储为字符串数组。
但是,我无法限制数组只包含唯一的字符串。
{ name: 'fail scenario', tags: ['bad', 'bad', 'array']}

我可以插入这条记录,但实际上应该是一个失败的场景。


我知道$addToSet,但我指的是Mongo Schema。 - Proximo
5个回答

8
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const _ = require('underscore');

let sampleSchema = new mongoose.Schema({
  name: {
    type: 'String',
    unique: true
  },
  tags: [{
    type: 'String'
  }]
})
sampleSchema.pre('save', function (next) {
  this.tags = _.uniq(this.tags);
  next();
});
const Sample = mongoose.model('sample', sampleSchema, 'samples');


router.post('/sample', function (req, res, next) {
  const sample = new Sample(req.body);

  sample.save()
    .then((sample) => {
      return res.send(sample);
    })
    .catch(err => {
      return res.status(500).send(err.message);
    })
});

谢谢你的回答,但我正在尝试只使用Schema来完成这个任务,而不是使用mongoose的代码或保存/更新方法中的标志。 - Proximo
在Underscore中,应该使用_.uniq而不是_.unique。此外,这里有一个修订版本,可以使用引用:this.tags = _.uniq(this.tags, function(i) {return (i._id) ? i._id.toString() : i;}); - BuffMcBigHuge

4

我得出的结论是,这无法通过Mongoose模式来实现。

JSON模式的编写方式如下。

let schema = {
   name: { type: 'string' }
   tags: { 
      type: 'array',
      items: { type: 'string', uniqueItems: true }
   }
}

在创建Mongo文档之前,我将使用JSON模式进行验证。

2

我来晚了,但也许这会在将来帮助到别人。

这段话与IT技术无关,只是一句话。
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: {
    type: String,
  },
  reference: {
    type: [mongoose.Schema.Types.ObjectId],
    ref: 'SomeOtherSchema',
    // Add a custom validator.
    validate: {
      // The actual validator function goes here.
      // "arr" will be the value that's being validated (so an array of 
      // mongoose new ObjectId statements, in this case).
      validator: arr => {
        // Convert all of the items in the array "arr", to their string
        // representations.
        // Then, use those strings to create a Set (which only stores unique
        // values).
        const s = new Set(arr.map(String));
        // Compare the Set and Array's sizes, to see if there were any
        // duplicates. If they're not equal, there was a duplicate, and
        // validation will fail.
        return s.size === arr.length;
      },
      // Provide a more meaningful error message.
      message: p => `The values provided for '${ p.path }', ` +
                    `[${ p.value }], contains duplicates.`,
    }
  },
});

上述代码应该是很容易理解的。

2

这种方法基于Med的答案,处理了引用,并完全在scheme验证中完成。

let sampleSchema = new mongoose.Schema({
    strings: [{type: 'String'}],
    references: [{type: mongoose.Schema.Types.ObjectId, ref: 'Reference'],
});

sampleSchema.pre('save', function (next) {

    let sample = this;

    sample.strings = _.uniq(sample.strings, function(i) {return (i._id) ? i._id.toString() : i;});
    sample.references = _.uniq(sample.references, function(i) {return (i._id) ? i._id.toString() : i;});

    return next();

});

1

在MongoDB的新版本中,您可以使用$addToSet将值添加到数组中,但仅当该值与数组中的项不重复时才会添加。

以下是参考链接: https://www.mongodb.com/docs/manual/reference/operator/update/addToSet/

以下是示例:

const SampleSchema = new mongoose.Schema({
    tags: [String]
});

const Sample = mongoose.model('Sample', SampleSchema);

// append to array only if value is unique
Sample.findByIdAndUpdate({_id: 1, {$addToSet: {tags: "New Tag"}}});

如果“新标签”不在tags数组中,则会有效地更新标签。否则,不执行任何操作。


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