一意のコレクションエントリを強制する方法があるかどうか疑問に思いましたただし、エントリがnullでない場合のみ。 eサンプルスキーマ:
var UsersSchema = new Schema({
name : {type: String, trim: true, index: true, required: true},
email : {type: String, trim: true, index: true, unique: true}
});
この場合の「電子メール」は必須ではありませんが、「電子メール」が保存されている場合は、このエントリが一意であることを確認する必要があります(データベースレベル)。
空のエントリは値「null」を取得するように見えるため、「unique」オプションでメールがクラッシュしないすべてのエントリ(メールを持たない別のユーザーがいる場合)。
今、私はアプリケーションレベルでそれを解決していますが、そのdbクエリを保存したいです。
tHX
MongoDB v1.8以降では、インデックスを定義するときにsparse
オプションをtrueに設定することにより、一意の値を保証するがフィールドなしで複数のドキュメントを許可するという望ましい動作を得ることができます。次のように:
email : {type: String, trim: true, index: true, unique: true, sparse: true}
またはシェルで:
db.users.ensureIndex({email: 1}, {unique: true, sparse: true});
一意のスパースインデックスでは、email
のvalueを持つnull
フィールドを持つ複数のドキュメントは許可されません。 、複数のドキュメントのみなしemail
フィールド。
はい、一意の「実際の」値を適用しながら、フィールドがnull
に設定されているか定義されていない複数のドキュメントを作成することができます。
要件:
string
でない場合は常にobject
またはnull
)。詳細に興味がない場合は、implementation
セクションに進んでください。
@Nolanの答えを補足するために、MongoDB v3.2以降では、フィルター式で部分的な一意のインデックスを使用できます。
部分フィルター式には制限があります。次のもののみを含めることができます。
- 等式(つまり、フィールド:値または
$eq
演算子)、$exists: true
式、$gt
、$gte
、$lt
、$lte
式、$type
式、$and
演算子は最上位のみ
これは、簡単な式{"yourField"{$ne: null}}
は使用できません。
ただし、フィールドが常に同じタイプを使用すると仮定すると、 $type
expression 。
{ field: { $type: <BSON type number> | <String alias> } }
MongoDB v3.6では、配列として渡すことができる複数の可能なタイプを指定するサポートが追加されました。
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
つまり、null
以外の場合、値は複数の型のいずれかになります。
したがって、以下の例のemail
フィールドにstring
または、たとえばbinary data
値、適切な$type
式は次のようになります。
{email: {$type: ["string", "binData"]}}
Mongooseスキーマで指定できます:
const UsersSchema = new Schema({
name: {type: String, trim: true, index: true, required: true},
email: {
type: String, trim: true, index: {
unique: true,
partialFilterExpression: {email: {$type: "string"}}
}
}
});
または、コレクションに直接追加します(ネイティブnode.jsドライバーを使用):
User.collection.createIndex("email", {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
});
db.collection('users').createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
},
function (err, results) {
// ...
}
);
db.users.createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {$type: "string"}
}
})
これにより、複数のレコードをnull
電子メールで挿入したり、電子メールフィールドをまったく使用せずに同じ電子メール文字列を挿入したりすることができます。
このトピックを調査している人たちへの簡単な更新。
選択した回答は機能しますが、代わりに部分インデックスの使用を検討することをお勧めします。
バージョン3.2で変更:MongoDB 3.2以降、MongoDBには部分インデックスを作成するオプションがあります。部分インデックスは、疎インデックスの機能のスーパーセットを提供します。 MongoDB 3.2以降を使用している場合、スパースインデックスよりも部分インデックスを優先する必要があります。
部分インデックスに関するその他のドキュメント: https://docs.mongodb.com/manual/core/index-partial/
実際、フィールドとして「email」が存在しない最初のドキュメントのみが正常に保存されます。 「電子メール」が存在しない場所での後続の保存は、エラーを発生させながら失敗します(以下のコードスニペットを参照)。理由については、ここで http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes でユニークインデックスとキーの欠落に関するMongoDB公式ドキュメントをご覧ください。
// NOTE: Code to executed in mongo console.
db.things.ensureIndex({firstname: 1}, {unique: true});
db.things.save({lastname: "Smith"});
// Next operation will fail because of the unique index on firstname.
db.things.save({lastname: "Jones"});
定義上、一意のインデックスでは、1つの値のみを1回しか保存できません。 nullをそのような値の1つと見なす場合、挿入できるのは1回だけです!アプリケーションレベルで確実に検証することで、アプローチは正しいです。それはそれができる方法です。
これを読むこともできます http://www.mongodb.org/display/DOCS/Querying+and+nulls