如何使用node js与mongoose创建一个唯一的json元素列表
How to create a unique list of json elements using node js with mongoose
我试图创建一个应用程序,用户添加到数据库的json文件。这个文件有三个属性:Name, Id和另一个值,我需要这个Id是唯一的,如果用户试图用这个Id创建另一个用户,他将得到一个错误消息。
我试图创建一个唯一的对象,但当然它没有工作(使用猫鼬场景):
var userSchema = mongoose.Schema({
list_users_ticket: {type: [{
whoChecked_name: String,
whoChecked_id: String,
what_checked: String
}], unique: true},
name : { type: String, required: true } ,
reg_id: { type: String, required: true, unique: true }
});
mongoose.createConnection('mongodb://------------');
var User = mongoose.model('User', userSchema);
// make this available to our users in our Node applications
module.exports = User;
我在dbRequests中是这样使用的:
exports.update = function(cur_reg_id, user_ticked) {
User.find({reg_id: cur_reg_id},function(err, users){
//removeusers(cur_reg_id);
if (err) throw err;
var len = users.length;
console.log("Len" + len)
if(len == 0 || len > 1){
callback({'response':"You didn't register"});
} else {
// Here I want to check if the value exist or not, and if yes, update the jsn filed like the code below :)
users[0].list_users_ticket.push(user_ticked);
console.log(users[0])
users[0].save(function(err) {
if (err) throw err;
callback({'response':"User Saved " + user_ticked});
});
}});
//console.log('User successfully updated!');
}
这段代码不适合我。我可以遍历列表中的所有元素,但这会在服务器中消耗大量的功率。
索引不是这样工作的。其目的是使元素在整个"集合"中是"唯一的",而不是在文档中,当然也不是在文档中的数组项
对于数组子文档的每个键都具有所有值的"唯一"项的非常简单的情况,那么答案是 $addToSet
。
但是这里有bug
虽然$addToSet
操作符在这里是正确的,但Mongoose目前并没有很好地发挥作用,特别是它正在重新排序要添加的对象中的键,从而使原本相同的对象不再相同。
从MongoDB的角度来看,如果键与数组中已经存在的对象的顺序不同,那么它就不是"相同"的,并且会添加一个新对象。这种重新排序使得$addToSet
作为操作符在这种情况下毫无用处。
唯一的解决方法是在键的顺序不重要的情况下测试数组中对象的存在,这通常是查询操作符的情况。因此,使用 $elemMatch
和 $not
条件应该可以达到目的:
{
"list_users_ticket": {
"$not": {
"$elemMatch": {
"whoChecked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
}
}
}
作为完整的演示:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/usertest');
mongoose.set("debug",true);
var ticketSchema = new Schema({
whoChecked_name: String,
whoChecked_id: String,
what_checked: String
},{ "_id": false });
var userSchema = new Schema({
list_users_ticket: [ticketSchema]
});
var User = mongoose.model( "User", userSchema );
var userData = {
whoChecked_name: "bob",
whoChecked_id: "1",
what_checked: "something"
};
var query = {
"list_users_ticket": {
"$not": {
"$elemMatch": userData
}
}
};
function logger(data) {
return JSON.stringify( data, undefined, 2 );
}
async.waterfall(
[
function(callback) {
User.remove({},function(err) {
callback(err);
})
},
function(callback) {
var user= new User({ "list_users_ticket": userData });
user.save(function(err,user) {
callback(err,user);
});
},
function(user,callback) {
console.log("Previous State: %s", logger(user));
query["_id"] = user._id;
User.findOneAndUpdate(
query,
{ "$push": { "list_users_ticket": userData } },
{ "new": true },
function(err,doc) {
if (err) callback(err);
console.log("Modified: %s", logger(doc));
callback();
}
);
},
function(callback) {
User.findOne({},function(err,user) {
if (err) callback(err);
console.log("Current: %s", logger(user));
callback();
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
与输出:Mongoose: users.remove({}) {}
Mongoose: users.insert({ _id: ObjectId("55cffae0b5fd68c324e6934b"), list_users_ticket: [ { whoChecked_name: 'bob', whoChecked_id: '1', what_checked: 'something' } ], __v: 0 })
Previous State: {
"__v": 0,
"_id": "55cffae0b5fd68c324e6934b",
"list_users_ticket": [
{
"whoChecked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
]
}
Mongoose: users.findAndModify({ _id: ObjectId("55cffae0b5fd68c324e6934b"), list_users_ticket: { '$not': { '$elemMatch': { whoChecked_name: 'bob', whoChecked_id: '1', what_checked: 'something' } } } }) [] { '$push': { list_users_ticket: { what_checked: 'something', whoChecked_id: '1', whoChecked_name: 'bob' } } } { new: true, upsert: false, remove: false }
Modified: null
Mongoose: users.findOne({}) { fields: undefined }
Current: {
"_id": "55cffae0b5fd68c324e6934b",
"__v": 0,
"list_users_ticket": [
{
"whoChecked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
]
}
这里的签入基本上确保在要插入的数据的数组中没有找到匹配的元素,否则将根本不匹配文档。虽然这与$addToSet
操作的行为不完全相同,但就是否将项添加到数组而言,结果是相同的。
根据您的需要,这可能需要也可能不需要做更多的工作,但是在执行这样的$addToSet
操作时,它是一种变通方法,直到做了一些事情来保留和不改变对象键的顺序。
原创内容
假设User
是关联模式的模型,并且从数据库中删除并清除了"index"约束。异步。瀑布也有助于这里的流:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/usertest');
mongoose.set("debug",true);
var ticketSchema = new Schema({
whoChecked_name: String,
whoChecked_id: String,
what_checked: String
},{ "_id": false });
var userSchema = new Schema({
list_users_ticket: [ticketSchema]
});
var User = mongoose.model( "User", userSchema );
var userData = {
whoChecked_name: "bob",
whoChecked_id: "1",
what_checked: "something"
};
function logger(data) {
return JSON.stringify( data, undefined, 2 );
}
async.waterfall(
[
function(callback) {
User.remove({},function(err) {
callback(err);
})
},
function(callback) {
var user= new User({ "list_users_ticket": userData });
user.save(function(err,user) {
callback(err,user);
});
},
function(user,callback) {
console.log("Previous State: %s", logger(user));
User.findByIdAndUpdate(user._id,
{ "$addToSet": { "list_users_ticket": userData } },
{ "new": true },
function(err,doc) {
if (err) callback(err);
console.log("Modified: %s", logger(doc));
callback();
}
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
这将表明,当您向"set"的成员添加"完全相同的细节"时,结果是没有添加任何额外的内容。
所以你点不是使用索引,而是控制逻辑,如所示。
大编辑
另一个巨大的猫鼬bug。以下是列出的代码中当前mongoose版本的详细信息:
Mongoose: users.remove({}) {}
Mongoose: users.insert({ _id: ObjectId("55cf60bc5fd3f5a70937190b"), list_users_ticket: [ { whoChecked_name: 'bob', whoChecked_id: '1', what_checked: 'something' } ], __v: 0 })
Previous State: {
"__v": 0,
"_id": "55cf60bc5fd3f5a70937190b",
"list_users_ticket": [
{
"whoChecked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
]
}
Mongoose: users.findAndModify({ _id: ObjectId("55cf60bc5fd3f5a70937190b") }) [] { '$addToSet': { list_users_ticket: { what_checked: 'something', whoChecked_id: '1', whoChecked_name: 'bob' } } } { new: true, upsert: false, remove: false }
Modified: {
"_id": "55cf60bc5fd3f5a70937190b",
"__v": 0,
"list_users_ticket": [
{
"whoChecked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
},
{
"what_checked": "something",
"whoChecked_id": "1",
"whoChecked_name": "bob"
}
]
}
查看新插入的"set"条目中的"键顺序"有何不同。仍然想知道MongoDB自己是如何接受这个的。
而标准节点驱动程序清单:
var async = require("async"),
mongodb = require("mongodb");
MongoClient = mongodb.MongoClient;
var userData = {
who_checked_name: "bob",
whoChecked_id: "1",
what_checked: "something"
};
MongoClient.connect('mongodb://localhost/usertest',function(err,db) {
function logger(data) {
return JSON.stringify( data, undefined, 2 );
}
var collection = db.collection('users');
async.waterfall(
[
function(callback) {
collection.remove({},function(err) {
console.log("did that");
callback(err);
});
},
function(callback) {
collection.insert({ "list_users_ticket": [userData] },function(err,doc) {
console.log("that too");
callback(err,doc);
});
},
function(user,callback) {
console.log( logger(user) );
collection.findOneAndUpdate(
{ "_id": user._id },
{ "$addToSet": { "list_users_ticket": userData } },
{ "returnOriginal": false },
function(err,doc) {
if (err) callback(err);
console.log( logger(doc) );
callback();
}
);
}
],
function(err) {
if (err) throw err;
db.close();
}
);
});
做正确的事情和期望的事情:
{
"result": {
"ok": 1,
"n": 1
},
"ops": [
{
"list_users_ticket": [
{
"who_checked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
],
"_id": "55cf62024cceb3ed181a7fbc"
}
],
"insertedCount": 1,
"insertedIds": [
"55cf62024cceb3ed181a7fbc"
]
}
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": "55cf62024cceb3ed181a7fbc",
"list_users_ticket": [
{
"who_checked_name": "bob",
"whoChecked_id": "1",
"what_checked": "something"
}
]
},
"ok": 1
}
- 根据对多个数组唯一的元素创建一个新数组
- Javascript:编写一个函数,接收一个数组,然后返回一个只有唯一数字的数组,只删除数组
- 多个ID和一个唯一的名称
- 如何在表单字段输入中生成一个简短的唯一代码号
- 如何生成一个唯一的链接,该链接将加载一个会话,其中包含客户端可用的某些文档
- 警告:数组或迭代器中的每个子节点都应该有一个唯一的“键”道具
- 为变量指定一个唯一的名称 JavaScript/jQuery
- 在 javascript 中 for 循环的每次迭代中声明一个新的、唯一的变量是一种好方法
- 未捕获的异常:每个数据元素都必须实现一个唯一的“id”属性slick.dataview.js
- 如何将用户名附加到我的 ./profile/
URL 中,以便每个用户都有一个唯一的页面.-意思 - - 如何在 javascript 中“唯一地”重复一个函数 n 次
- PouchDB:创建一个设计文档来获取唯一键
- 每次 while 循环运行时调用 javascript,以从数据库中给出一个唯一的时间
- 避免使用下一个url,直到类别名称是唯一的
- 在DOM中单击即可获得下一个也是唯一一个类
- 选择包含每个唯一字段值的行,并按另一个具有限制的字段排序
- 输出一个结果数组,其中包含给定数组的唯一元素的分组计数
- 将一个元素与一个唯一的数字相关联
- 如何消除阵列中的重复?(不是唯一的,但删除下一个值)PHP
- 弹出窗体悬停-如何使它在页面上的唯一一个