用Mongoose增加一个数字字段?用于在.find上排序结果

时间:2014-04-03 18:05:19

标签: javascript node.js mongodb sorting mongoose

我有一个像这样的猫鼬模型:

module.exports = mongoose.model('Item', {
    text : String,
    position: Number
});

我希望有一个位置字段,在所有文档的.length之类的位置递增,用于对.find的全部结果进行排序:

// 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自动填充位置字段的数字?

// 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);
    });

});

2 个答案:

答案 0 :(得分:1)

Mongoose允许您挂钩savevalidateremove方法,并在执行代码之前和之后执行代码。

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

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);

More here

在验证开始之前,计算项目数。然后,设置位置 在上述代码准备好之前,验证和其他预验证器**钩子不会开始。

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

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


在预验证钩子中,您可以在else-case中放置一些逻辑。插入具有现有Item值的position时,您需要将每条记录向下移动。您可以通过执行以下操作来执行此操作:

  1. 使用this.isModified("position")检查自上次保存以来值是否已更改。您可能还需要doc.isNew()。
  2. 检查是否存在具有相同position的现有文档。像Item.where({_id: {$ne: this._id}, position: this.position}).count()
  3. 之类的东西
  4. 如果有,请执行:Item.update({position: {$gte: this.position}}, {position: {$inc: 1}}, {multi: 1})
  5. 然后调用next()来保存您的文档。
  6. 以上应该有效。但是,当您删除文档时,它会留下空白。

    另外,查看索引。您需要在位置字段中添加一个。甚至可能是unique index

答案 1 :(得分:0)

Per @ RikkusRukkus将记录向下移动的步骤,这是其他情况(待测试)的逻辑

// 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);