《Nodejs开发指南》的问题-E11000 duplicate key error index: microblog.posts.$user_1 dup key: { : null}

《Nodejs开发指南》的问题-E11000 duplicate key error index: microblog.posts.$user_1 dup key: { : null}

再做博客系统的时候,不知道为什么老是报错——MongoError: E11000 duplicats key error index: microblog.posts.$user_1 dup key: { : null}

相关代码如下,请大神帮忙看看吧

post.js代码 var mongodb = require(’./db’);

function Post (username, post, time) { this.user = username; this.post = post; if(time){ this.time = time; }else{ this.time = new Date(); } }

module.exports = Post;

Post.prototype.save = function save(callback) { //存入mongoDB的文档 var post = { user : this.user, to : “to”, post : this.post, time : this.time };

mongodb.open(function(err, db){ if(err){ return callback(err); }

//读取posts集合 db.collection(‘posts’, function(err, collection){ if(err){ mongodb.close(); return callback(err); }

collection.ensureIndex(‘user’,{ unique:true },{w: 0}); collection.insert(post,{safe: true}, function(err, posts){ mongodb.close(); console.log(err) console.log(posts +“我”) callback(err, posts); }); //为user属性添加索引

}); }); };

Post.get = function get(username, callback){ mongodb.open(function(err, db){ if(err){ return callback(err); } //读取posts集合 db.collection(‘posts’, function(err, collection){ if(err){ mongodb.close(); return callback(err); }

//查找user属性为username的文档,如果username是null则匹配全部 var query = {}; if(username){ query.user = username; } collection.find(query).sort({time: -1}).toArray(function(err, docs){ mongodb.close(); if(err){ callback(err, null); } //封装posts为Post对象 var posts = []; docs.forEach(function(doc, index){ var post = new Post(doc.user, doc.post, doc.time); posts.push(post); }); callback(null, posts); }) }); }); };

index.js代码

/*

  • GET home page. */; var crypto = require(‘crypto’), User = require(’…/modules/user.js’), Post = require(’…/modules/Post.js’);

module.exports = function(app){ app.get(’/’, function(req, res){ Post.get(null, function(err, posts){ if(err){ posts = []; } res.render(‘index’, { title: ‘首页’, posts: posts ,user:req.session.user, success:req.flash(‘success’).toString(), error:req.flash(‘error’).toString() }); }); });

app.get(’/reg’, checkNotLogin); app.get(’/reg’, function(req, res){ res.render(‘reg’, { title : ‘用户注册’ ,user:req.session.user, success:req.flash(‘success’).toString(), error:req.flash(‘error’).toString() }); });

app.post(’/reg’, checkNotLogin); app.post(’/reg’, function(req, res){

//检验用户两次输入的口令是否一致 if (req.body[‘password-repeat’] != req.body[‘password’]) { req.flash(‘error’, “密码不一致”); return res.redirect(’/reg’); }

//生成口令的散列值 var md5 = crypto.createHash(‘md5’); var password = md5.update(req.body.password).digest(‘base64’);

var newUser = new User({ name : req.body.username, password : password });

//检查用户名是否存在 User.get(newUser.name, function(err, user){ if(user){ err = ‘用户存在’; } if(err){ req.flash(‘error’, err); return res.redirect(’/reg’); } //如果不存在则新增用户 newUser.save(function(err){

 if(err){
  req.flash('error', err.stack);
  return res.redirect('/reg');
 }
 req.session.user = newUser;
 req.flash('success', '注册成功');
 res.redirect('/');
})

}) });

app.get(’/login’, checkNotLogin); app.get(’/login’, function(req, res){ res.render(‘login’, { title: ‘用户登录’ ,user:req.session.user, success:req.flash(‘success’).toString(), error:req.flash(‘error’).toString() }); });

app.post(’/login’, checkNotLogin); app.post(’/login’, function(req, res){ //生成口令的散列值 var md5 = crypto.createHash(‘md5’); var password = md5.update(req.body.password).digest(‘base64’);

User.get(req.body.username, function(err, user){ if(!user){ req.flash(‘error’, “用户不存在”); return res.redirect(’/login’); } if(user.password != password){ req.flash(‘error’, ‘用户口令错误’); return res.redirect(’/login’); } req.session.user = user; req.flash(‘success’, ‘登入成功’); res.redirect(’/’); }); });

app.get(’/logout’, checkLogin); app.get(’/logout’, function(req,res){ req.session.user = null; req.flash(‘success’, ‘登出成功’); res.redirect(’/’); }); /* app.get(’/post’, checkNotLogin); app.post(’/post’, function(req, res){ res.render(‘user’, { title: ‘用户发表’ ,user:req.session.user, success:req.flash(‘success’).toString(), error:req.flash(‘error’).toString() }); }); */ app.post(’/post’, checkLogin); app.post(’/post’, function(req, res){ var currentUser = req.session.user; var post = new Post(currentUser.name, req.body.post); post.save(function(err){ if(err){ req.flash(‘error’, err); console.log(“我2” +"+" +post.user +"-" + post.user +"-"+post.post) return res.redirect(’/’); } console.log(“我”) req.flash(‘success’, ‘发表成功’); res.redirect(’/u/’ + currectUser.name); }); });

app.get(’/u/:user’, function(req, res){ User.get(req.params.user, function(err, user){ if(!user){ req.flash(‘error’, ‘用户不存在’); return res.redirect(’/’); } Post.get(user.name, function(err, posts){ if(err){ req.flash(‘error’, err); return res.redirect(’/’); } res.render(‘user’, { title: user.name, posts: posts }); }); }); }); };

function checkLogin (req, res, next){ if(!req.session.user){ req.flash(‘error’, ‘未登录’); return res.redirect(’/login’); } next(); }

function checkNotLogin (req, res, next){ if(req.session.user){ req.flash(‘error’, ‘已登录’); return res.redirect(’/’); } next(); }


6 回复

根据你提供的错误信息和代码,错误 E11000 duplicate key error index: microblog.posts.$user_1 dup key: { : null} 表明在尝试向 MongoDB 的 microblog.posts 集合中插入具有 null 值的 user 字段时发生了重复键错误。这通常是因为在数据库中已经存在一个 user 字段为 null 的文档。

问题分析

从代码来看,你在 save 方法中创建了一个新文档,并尝试插入到 posts 集合中。如果 user 字段没有正确设置,可能会导致插入失败。

解决方案

1. 确保 user 字段非空

确保在调用 save 方法之前,user 字段已经被正确赋值。你可以在 save 方法中添加一些逻辑来检查 user 是否为空。

Post.prototype.save = function save(callback) {
    // 存入mongoDB的文档
    var post = {
        user: this.user,
        to: "to",
        post: this.post,
        time: this.time
    };

    // 检查 user 是否为空
    if (!post.user) {
        return callback(new Error("User cannot be null"));
    }

    mongodb.open(function(err, db) {
        if (err) {
            return callback(err);
        }

        db.collection('posts', function(err, collection) {
            if (err) {
                mongodb.close();
                return callback(err);
            }

            collection.ensureIndex('user', { unique: true }, { w: 0 });
            collection.insert(post, { safe: true }, function(err, posts) {
                mongodb.close();
                console.log(err);
                console.log(posts + "我");
                callback(err, posts);
            });
        });
    });
};

2. 更新 get 方法

确保在查询 posts 时不会返回 usernull 的文档。

Post.get = function get(username, callback) {
    mongodb.open(function(err, db) {
        if (err) {
            return callback(err);
        }

        db.collection('posts', function(err, collection) {
            if (err) {
                mongodb.close();
                return callback(err);
            }

            // 查找 user 属性为 username 的文档,如果 username 是 null 则匹配全部
            var query = {};
            if (username) {
                query.user = username;
            }

            // 过滤掉 user 为 null 的文档
            if (query.user === null) {
                query.user = { $ne: null };
            }

            collection.find(query).sort({ time: -1 }).toArray(function(err, docs) {
                mongodb.close();
                if (err) {
                    callback(err, null);
                }

                // 封装 posts 为 Post 对象
                var posts = [];
                docs.forEach(function(doc, index) {
                    var post = new Post(doc.user, doc.post, doc.time);
                    posts.push(post);
                });
                callback(null, posts);
            });
        });
    });
};

总结

通过上述修改,确保在插入文档时 user 字段不为 null,并且在查询文档时过滤掉 usernull 的文档。这样可以避免出现 E11000 duplicate key error 错误。


注意你建立了一个唯一索引: collection.ensureIndex(‘user’,{ unique:true },{w: 0}); 出现这个问题应该是你的posts中出现重复的user了。

在注册的时候,也有一个这样的索引。也是用user做的索引。在post中也是用user做的。就重复了,有没有解决的方法呢?

user.js代码

var mongodb = require(’./db’);

function User (user) { this.name = user.name; this.password = user.password; }

module.exports = User;

User.prototype.save = function save(callback) { var user = { name: this.name, password: this.password, };

mongodb.open(function(err, db){ if(err){ return callback(err); }

db.collection(‘users’, function(err, collection){ if(err){ mongodb.close(); return callback(err); } /* collection.remove(user,function(err,result){ console.log(result); }); */ collection.ensureIndex(‘name’,{ unique:true },{w: 0}); collection.insert(user,{safe: true}, function(err, user){ mongodb.close(); console.log(err) console.log(user) callback(err, user); }); }); }); };

User.get = function get(username, callback){ mongodb.open(function(err, db){ if(err){ return callback(err); }

db.collection(‘users’, function(err, collection){ if(err){ mongodb.close(); return callback(err); }

collection.findOne({ name: username },function(err, doc){ mongodb.close(); if(doc){ var user = new User(doc); callback(err, user); } else { callback(err, null); } }); }); }); };

你这两个地方索引是不一样的,如果你想不加入重复,可以添加如下选项来删除重复的:

collection.ensureIndex('user', {unique:true,dropDups:true}, {w: 0});

但是这样无法保证会删除哪一条。最好的办法其实你可以在save之前做个唯一验证,防止加入重复。

当然你得考虑这个唯一是否是必要的(根据业务需求来),如果不必要,就不要加unique:true

从你提供的代码来看,问题在于user字段在MongoDB中被设置为了唯一索引(unique: true),而你在某些情况下尝试插入null作为user字段的值,这违反了唯一性约束。

解决方法

  1. 确保用户非空: 在保存文章时,确保user字段不为空。可以使用默认值或其他机制来处理这种情况。

  2. 修改索引: 如果确实需要允许null值作为唯一键,可以调整索引定义,使其允许null值,但通常唯一索引不允许重复的null值。

示例代码

post.js中,可以在保存之前检查user字段是否为空,并进行适当的处理:

Post.prototype.save = function save(callback) {
    var post = {
        user: this.user || "anonymous", // 默认值为"anonymous"
        to: "to",
        post: this.post,
        time: this.time
    };

    mongodb.open(function(err, db) {
        if (err) {
            return callback(err);
        }

        db.collection('posts', function(err, collection) {
            if (err) {
                mongodb.close();
                return callback(err);
            }

            // 为user属性添加索引
            collection.ensureIndex('user', { unique: true }, { w: 0 });

            collection.insert(post, { safe: true }, function(err, posts) {
                mongodb.close();
                console.log(err);
                console.log(posts + "我");
                callback(err, posts);
            });
        });
    });
};

解释

  • 默认值:在保存文章时,如果user字段为空,则使用默认值 "anonymous"
  • 索引调整:保持索引不变,因为MongoDB默认不允许多个文档具有相同的null值作为唯一键。

通过这种方式,你可以避免插入包含null值的文档,从而解决E11000错误。

回到顶部