简体   繁体   English

用猫鼬增加数字字段? 用于在.find上对结果进行排序

[英]Increment a number field with Mongoose? For sorting results on .find

I have a mongoose model that looks like this: 我有一个看起来像这样的猫鼬模型:

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

And I'm looking to have a Position field that increments on something like the .length of all the documents, for sorting the results of a .find of All: 我正在寻找一个位置字段,该字段在所有文档的.length之类的地方递增,以便对All .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
    });
});

Is there a way to auto-fill a number for the Position field with some javascript in node.js? 有没有一种方法可以使用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 lets you hook into the save , validate and remove methods and execute code before and after they're executed. Mongoose使您可以进入savevalidateremove方法,并在执行之前和之后执行代码。

This code can be asynchronous. 该代码可以是异步的。 For example, in your case you could probably do this: 例如,您可能会这样做:

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 . 这里更多

Before validation starts, the number of Items is counted. 在验证开始之前,将对项目数进行计数。 Afterwards, the position is set. 然后,设置位置。
Validation and other pre-validator ** hooks will not commence until the above code is ready. 在上述代码准备就绪之前,验证和其他预验证器**挂钩将不会开始。

* I'm using mongoose.model here to fetch the model because the model is not compiled yet (that happens a bit below). *我在这里使用mongoose.model来获取模型,因为该模型尚未编译(在下面发生)。

** The documentation shows you how you can make multiple pre-validator hooks execute in parallel. **文档向您展示了如何使多个预验证器挂钩并行执行。 I've chosen not to do this in this example because the code is easier to read and because you might actually need the validators to run sequentially. 在本示例中,我选择不执行此操作,因为代码更易于阅读,并且因为您可能实际上需要验证程序才能按顺序运行。


In the pre-validation hook, you could place some logic in the else-case. 在预验证挂钩中,您可以在其他情况下放置一些逻辑。 When inserting an Item with an existing position value, you'll want to move every record down. 当插入具有现有position值的Item时,您需要向下移动每条记录。 You can do this by doing the following: 您可以通过执行以下操作来做到这一点:

  1. Use this.isModified("position") to check if the value was changed since you last saved. 使用this.isModified("position")检查自上次保存以来该值是否已更改。 You might also need doc.isNew(). 您可能还需要doc.isNew()。
  2. Check if there is an existing document with the same position . 检查是否存在相同position的现有文档。 Something like Item.where({_id: {$ne: this._id}, position: this.position}).count() 类似于Item.where({_id: {$ne: this._id}, position: this.position}).count()
  3. If there is, execute: Item.update({position: {$gte: this.position}}, {position: {$inc: 1}}, {multi: 1}) 如果存在,请执行: Item.update({position: {$gte: this.position}}, {position: {$inc: 1}}, {multi: 1})
  4. Then call next() to save your doc. 然后调用next()保存您的文档。

The above should work. 以上应该可以。 It will leave gaps when you remove documents however. 但是,当您删除文档时,它将留下空白。

Also, look into indexes. 另外,查看索引。 You'll want to add one on the position field. 您需要在位置字段中添加一个。 Perhaps even a unique index . 也许甚至是unique index

Per @RikkusRukkus's steps for moving records down, here's logic for the else-case (to be tested) 根据@RikkusRukkus向下移动记录的步骤,这是else情况(待测试)的逻辑

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM