Javascript 用猫鼬增加一个数字字段?用于对上的结果进行排序。查找

Javascript 用猫鼬增加一个数字字段?用于对上的结果进行排序。查找,javascript,node.js,mongodb,sorting,mongoose,Javascript,Node.js,Mongodb,Sorting,Mongoose,我有一个猫鼬模型,看起来像这样: module.exports = mongoose.model('Item', { text : String, position: Number }); 我希望有一个Position字段,它以所有文档的.length为增量,用于对.find of all的结果进行排序: // get All Items app.get('/itemsList', function(req, res) { // use mongoose to get

我有一个猫鼬模型,看起来像这样:

module.exports = mongoose.model('Item', {
    text : String,
    position: Number
});
我希望有一个Position字段,它以所有文档的.length为增量,用于对.find of all的结果进行排序:

// get All Items
app.get('/itemsList', function(req, res) {

    // use mongoose to get all items in the database
    Item.find({
        sort : { position: 1 } // sort by Ascending Position
    }. function(err, items) {

        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        res.json(items); // return all items in JSON format
    });
});
有没有办法在node.js中用一些javascript自动填充Position字段的数字

// create an item
app.post('/api/item', function(req, res) {

    // create an item, information comes from AJAX request from Angular
    Item.create({
        text : req.body.text,
        position:
        // something using ++items.length
    }, function(err, item) {
        if (err)
            res.send(err);
    });

});

Mongoose允许您钩住
保存
验证
删除
方法,并在执行前后执行代码

此代码可以是异步的。例如,在您的情况下,您可能可以这样做:

var schema = mongoose.Schema({
    text : String,
    position: Number
});
schema.pre("validate", function(next) {
    var doc = this;

    // If 'position' is not filled in, fill it in.
    // Not using !position because 0 might be a valid value.
    if(typeof position !== "number") {
        // Count the number of Items *
        mongoose.model("Item").count(function(err, num) {
            // If there was an error, pass it to next().
            if(err)
                return next(err);

            // Update the position, then call next();
            doc.position = num;
            return next();
        });
    } else {
        //  There is no need to count, so call next().
        next();
    }
});
module.exports = mongoose.model('Item', schema);

在验证开始之前,将统计项目数。然后,设置位置。
验证和其他预验证程序**钩子在上述代码准备就绪之前不会开始

*我在这里使用mongoose.model来获取模型,因为模型还没有编译(发生在下面)

**文档向您展示了如何使多个预验证器挂钩并行执行。在本例中,我选择不这样做,因为代码更易于阅读,而且您可能实际上需要验证程序按顺序运行


在预验证钩子中,您可以在else案例中放置一些逻辑。插入带有现有
位置值的
时,您需要向下移动每条记录。您可以通过执行以下操作来完成此操作:

  • 使用
    this.isModified(“position”)
    检查自上次保存以来该值是否已更改。您可能还需要doc.isNew()
  • 检查是否存在具有相同
    位置的现有文档
    。类似于
    Item.where({u-id:{$ne:this.\u-id},position:this.position})。count()
  • 如果有,则执行:
    Item.update({position:{$gte:this.position},{position:{$inc:1},{multi:1})
  • 然后调用next()保存您的文档
  • 上述措施应该有效。但是,当您删除文档时,它会留下间隙


    此外,请查看索引。您需要在“位置”字段中添加一个。甚至可能是一个
    唯一索引

    根据@RikkusRukkus的记录下移步骤,下面是else案例的逻辑(待测试)


    谢谢你。。真是太棒了!对于创建app.post Item.create调用,由于架构自动填充位置字段,我是否省略了该字段?是的,您可以将
    位置
    从传递给
    Item.create的对象中删除。当然,如果你知道你想要什么值,你仍然可以指定它。。很多人都犯了一个小错误,现在正在编辑。我将添加一个示例,说明如果两个位置值恰好相同,如何解决冲突。非常酷。将播放移动每个记录下来-感谢的步骤。索引看起来确实更好,唯一索引会更好。。有没有关于如何将他们合并的提示?我已经修改了你的评论(在它出现之前需要检查),以包括以下更改:update语句需要回调,并且
    next
    并不总是被调用。在我看来,这在概念上很好,所以请尝试看看这是否适合您。:-)@RikkusRukkus刚刚开始测试这个,并且
    typeof position!==“数字”
    不包括手动输入的数字。。尽管所有文档的数量都在增加,这真是太棒了!如果需要的话,有没有关于替代方案的建议?
    // load mongoose since we need it to define a schema and model
    var mongoose = require('mongoose');
    
    var ItemSchema = mongoose.Schema({
        text : String,
        position: Number
    });
    
    // before validation starts, the number of Items is counted..afterwards, the position is set
    ItemSchema.pre("validate", function(next) {
    
        var doc = this;
    
        // if 'position' is not filled in, fill it in..not using !position because 0 might be a valid value
        if(typeof position !== "number") {
            // count the number of Items *
            // use mongoose.model to fetch the model because the model is not compiled yet
            mongoose.model("Item").count(function(err, num) {
                // if there was an error, pass it to next()
                if(err)
                    return next(err);
    
                // set the position, then call next();
                doc.position = num;
                return next();
            });
        } else if(this.isModified("position") || this.isNew()) {
            // check if there is an existing document with the same position
            // use mongoose.model to fetch the model because the model is not compiled yet
            mongoose.model("Item").where({_id: {$ne: this._id}, position: this.position}).count( function (err, count) {
    
                // if there was an error, pass it to next()
                if(err)
                    return next(err);
    
                // if there is a doc with the same position, execute an update to move down all the $gte docs
                if(count > 0) {
                    // use mongoose.model to fetch the model because the model is not compiled yet
                    mongoose.model("Item").update({position: {$gte: this.position}}, {position: {$inc: 1}}, {multi: 1}, function(err, numAffected) {
                        // Call next() (with or without an error)
                        next(err);
                    });
    
                } else {
                    //  there are no docs that need to move down, so call next()
                    next();
                }
            });
        } else {
            //  there is no need to count or update positions, so call next()
            next();
        }
    });
    
    module.exports = mongoose.model('Item', ItemSchema);