node.js - 在单个查询中从 Mongo DB 中删除最新文档

标签 node.js mongodb mongoose mongodb-query

我想通过单个查询从我的 MongoDB 中删除最新文档。

我尝试了一些命令,但它们似乎不起作用。

最佳答案

您正在寻找的基本操作是findOneAndDelete()在 Mongoose 中,这是一个原子操作,返回“已删除”文档和响应。这只会影响单个文档,您可以通过在选项中应用排序规范来获得“最后一个”文档。

对于“最后”,您基本上有两个选项,要么是通过包含您存储在可以排序的文档中的 BSON“日期”属性的字段:

Model.findOneAndDelete(
   { "field": "a" },
   { "sort": { "date": -1 } }
)

或者通过使用 _id 字段(其中使用了 ObjectId),因为没有任何其他干预,该值将随着每个插入的文档“始终增加”:

Model.findOneAndDelete(
   { "field": "a" },
   { "sort": { "_id": -1 } }
)

如果您没有在文档中存储带有 BSON 日期的字段作为确定“最新插入”或“上次修改”的方法,那么这通常是您的选择。如果您想要“最后修改”,那么您实际上没有其他选择可以在文档中记录此类 BSON 日期属性,因为 _id 本身是不可变的并且不会更改,并且当您没有显式存储任何其他字段来记录此类信息时,充其量是“创建日期”的“后备”。

下面是一个完整的示例,它演示了将多个文档添加到集合中,然后仅“删除”满足所提供的查询条件的“最后一个”文档。演示了两者都使用存储日期和 _id 字段:

const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost/test';

mongoose.Promise = global.Promise;
mongoose.set('debug', true);

const testSchema = new Schema({
  field: String,
  other: String,
  date: Date
});

const Test = mongoose.model('Test', testSchema);

const log = data => console.log(JSON.stringify(data, undefined, 2));


(async function() {

  const now = Date.now();
  const today = now - (now % (1000 * 60 * 60 * 24));

  try {
    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    await Test.insertMany([
      ...[ ...Array(4)].map((e,i) =>
        ({
           field: "a",
           ...(i === 3) ? { other: "last" }
            : (i === 2) ? { other: "second last" } : {},
           date: new Date(today + (i * 1000 * 60 * 60 * 24))
        })
      ),
      { field: "b", date: new Date(today + (5 * 1000 * 60 * 60 * 24)) }
    ]);

    let removed = await Test.findOneAndDelete(
      { field: "a" },
      { sort: { "date": -1 } }
    );

    log({ removed });

    let remaining = await Test.find();
    log({ remaining });

    let next_removed = await Test.findOneAndDelete(
      { field: "a" },
      { sort: { "_id": -1 } }
    );
    log({ next_removed });

    let still_remaining = await Test.find();
    log({ still_remaining });

    mongoose.disconnect();

  } catch(e) {
    console.error(e)

  } finally {
    process.exit()
  }

})()

这将返回预期输出:

Mongoose: tests.remove({}, {})
Mongoose: tests.insertMany([ { _id: 5b0cb4a60cf8000c7ebd4402, field: 'a', date: 2018-05-29T00:00:00.000Z, __v: 0 }, { _id: 5b0cb4a60cf8000c7ebd4403, field: 'a', date: 2018-05-30T00:00:00.000Z, __v: 0 }, { _id: 5b0cb4a60cf8000c7ebd4404, field: 'a', other: 'second last', date: 2018-05-31T00:00:00.000Z, __v: 0 }, { _id: 5b0cb4a60cf8000c7ebd4405, field: 'a', other: 'last', date: 2018-06-01T00:00:00.000Z, __v: 0 }, { _id: 5b0cb4a60cf8000c7ebd4406, field: 'b', date: 2018-06-03T00:00:00.000Z, __v: 0 } ], {})
Mongoose: tests.findOneAndDelete({ field: 'a' }, { sort: { date: -1 } })
{
  "removed": {
    "_id": "5b0cb4a60cf8000c7ebd4405",
    "field": "a",
    "other": "last",
    "date": "2018-06-01T00:00:00.000Z",
    "__v": 0
  }
}
Mongoose: tests.find({}, { fields: {} })
{
  "remaining": [
    {
      "_id": "5b0cb4a60cf8000c7ebd4402",
      "field": "a",
      "date": "2018-05-29T00:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5b0cb4a60cf8000c7ebd4403",
      "field": "a",
      "date": "2018-05-30T00:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5b0cb4a60cf8000c7ebd4404",
      "field": "a",
      "other": "second last",
      "date": "2018-05-31T00:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5b0cb4a60cf8000c7ebd4406",
      "field": "b",
      "date": "2018-06-03T00:00:00.000Z",
      "__v": 0
    }
  ]
}
Mongoose: tests.findOneAndDelete({ field: 'a' }, { sort: { _id: -1 } })
{
  "next_removed": {
    "_id": "5b0cb4a60cf8000c7ebd4404",
    "field": "a",
    "other": "second last",
    "date": "2018-05-31T00:00:00.000Z",
    "__v": 0
  }
}
Mongoose: tests.find({}, { fields: {} })
{
  "still_remaining": [
    {
      "_id": "5b0cb4a60cf8000c7ebd4402",
      "field": "a",
      "date": "2018-05-29T00:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5b0cb4a60cf8000c7ebd4403",
      "field": "a",
      "date": "2018-05-30T00:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5b0cb4a60cf8000c7ebd4406",
      "field": "b",
      "date": "2018-06-03T00:00:00.000Z",
      "__v": 0
    }
  ]
}

NOTE: For the actual Node Driver it's findOneAndDelete() is essentially identical and is the actual call made by mongoose to the server, but older versions of mongoose only support findOneAndRemove() which is almost identical in options but instead issues a findAndModify() request through the core API.

From a technical standpoint these are all actually the findAndModify command, however it is generally preferred to use the modern API since the methods have "clarity" in their intended purpose, and also choose reasonable "defaults" to the range of available options to the broader "command" which the server actually processes.

关于node.js - 在单个查询中从 Mongo DB 中删除最新文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50568108/

相关文章:

node.js - 排除嵌套对象中的 Mongoose 表字段

javascript - nodejs promise 数组,我该怎么做?

node.js - node.js 的断言库?

node.js - Xively 和 Node-Red

python - 如何根据各种 URL 参数和请求值让 eve 写入不同的数据库?

javascript - 使用 Node.js 监控 Mongo 的更改

node.js - 使用 django 和 nodejs 为 websocket 设置 nginx 的配置(wss ://)

javascript - 如果特定列包含特定值,MongoDB 规则将删除行

node.js - MongoDB 初始连接慢

javascript - 在 promise 中运行同步功能