# @expander/mongoose-tracker 中文文档

规范地址：https://npmcn.com/package/%40expander/mongoose-tracker/

版本：1\.8\.2
npm 元数据更新时间：2026-01-13T14:57:49.990Z
中文译文更新时间：2026-11-14T08:21:21.754Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40expander/mongoose-tracker
原文对照：https://npmcn.com/package/%40expander/mongoose-tracker/?lang=original
项目主页：https://github.com/expandertech/mongoose-tracker#readme
源码仓库：https://github.com/expandertech/mongoose-tracker

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1.7 MB，10 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.0\.0
- 运行依赖：1 个
- peer 依赖：mongoose ^6\.1\.5
- 首次发布：2024-12-09T12:01:55.290Z
- 最新版本发布：2026-01-13T14:57:49.766Z
- 近 30 天下载量：2105（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：20（近 12 个月 3 个）

## 中文简介

是一个 mongoose 插件, 它会自动跟踪文档创建、 更新和可选修改部分字段的时间

## 安装

```sh
npm install @expander/mongoose-tracker
```

也可以使用：`pnpm add @expander/mongoose-tracker`、`yarn add @expander/mongoose-tracker`、`bun add @expander/mongoose-tracker`

## README

# 巨鹅追踪器

**巨鹅追踪器** 是一个多功能的 Mongoose 插件,可以自动跟踪文档的创建和更新。 它仔细地记录了特定字段的更改,包括嵌入字段,数组,并引用了其他文档,提供了全面的修改历史. 此插件会增强您 MongoDB 收藏中的数据完整性和可审计性 .

受到 [动物可追踪](https://www.npmjs.com/package/@folhomee-public/mongoose-tracker) 软件包, **巨鹅追踪器** 提供更好的功能和定制 与你的Mongoose计划无缝结合.

## 目录

-   [特征](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-features)
-   [安装](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-installation)
-   [使用量](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-usage)
    -   [插件配置](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-plugin-configuration)
    -   [选项](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-options)
    -   [示例Schema 用法](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-example-schema-usage)
    -   [使用更改By来记录更改](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-using-_changedby-to-record-changes)
    -   [Display 字段的重要性](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-importance-of-the-_display-field)
    -   [跟踪阵列字段](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-tracking-array-fields)
-   [捐款](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-contributing)
-   [法律](https://npmcn.com/package/%40expander/mongoose-tracker/#readme-legal)

* * *

## 特征

-   跟踪您 Mongoose 文档中的字段变化.
-   支持嵌入对象.
-   支持数组元素(检测已添加/删除的项目).
-   支持引用( I)`ObjectId`)到其他Mongoose文件(如果有的话,将存储“显示”值).
-   允许忽略某些字段(例如:. `_id`, (中文(简体) ), `__v`(见a/c.5/49/70,附件).
-   保持历史条目可配置的最大长度.

* * *

## 安装

安装 **巨鹅追踪器** 通过 npm :

```bash
npm install @expander/mongoose-tracker
```

或

```
yarn add @expander/mongoose-tracker
```

* * *

## 使用量

### 插件配置

```js
import mongoose, { Schema } from "mongoose";
import mongooseTracker from "@expander/mongoose-tracker"; // Adjust import based on your actual package name

const YourSchema = new Schema({
  title: String,
  orders: [
    {
      orderId: String,
      timestamp: Date,
      items: [ { name: String, price:Number, .... }, ],
      // ...other fields...
    }
  ],
  user: {
    firstName: String,
    lastName:String,
    // ...other fields...
  }
  // ...other fields...
});

// Apply the plugin with options
YourSchema.plugin(mongooseTracker, {
  name: "history",
  fieldsToTrack: [
    "title",
    "user.firstName",
    "user.lastName",
    "orders.$.items.$.price",
    "orders.$.items.$.name",
    "orders.$.timestamp",
  ],
  fieldsNotToTrack: ["history", "_id", "__v", "createdAt", "updatedAt"],
  limit: 50,
  instanceMongoose: mongoose, //optional.
  logLevel: 'info', // Optional: 'debug' | 'info' | 'warn' | 'error' | 'none' (default: 'none')
});

export default mongoose.model("YourModel", YourSchema);
```

#### 它会做什么

1.  **添加历史字段**: 添加一个调用字段 `history` (默认)到您的计划, 存储变化的历史 .
    
2.  **监视文档更改**: 监视期间的变化 `save` 业务和基于特定查询的更新`findOneAndUpdate`, (中文(简体) ), `updateOne`, (中文(简体) ), `updateMany`) (中文(简体) ).
    
    > **说明**: 当前, 插件最符合 `save` 用于跟踪变化的方法。 我们正积极努力加强对其他更新钩的支持,以确保在所有更新行动中全面跟踪变化.
    
3.  **详细更改**:每次更改时记录一个条目,存储更改的用户/系统(`_changedBy`如果提供的话.
    

### 选项

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| **`name`** | `string` | `'history'` | 存储历史记录的阵列字段名称 . |
| **`fieldsToTrack`** | `string[]` | `[]` (空虚) | 要跟踪的字段模式列表 。 若为空相, **所有字段** (单位:千美元) `fieldsNotToTrack`)被跟踪. |
| **`fieldsNotToTrack`** | `string[]` | `['history', '_id', '_v', '__v', 'createdAt', 'updatedAt', 'deletedAt', '_display']` | 字段/路径 **排除** 从跟踪. |
| **`limit`** | `number` | `50` | 要保留在历史阵列中的最大历史项数 . |
| **`instanceMongoose`** | `mongoose` | 默认导入 `mongoose` 实例 | 如果你有另外的Mongoose实例的话,就取消. |
| **`logLevel`** | `string` | `'none'` | 日志级别 : `'debug'`, (中文(简体) ), `'info'`, (中文(简体) ), `'warn'`, (中文(简体) ), `'error'`,或 `'none'`。 。 。 . |
| **`logger`** | `Logger` | 默认控制台日志 | 自定义日志实例(如温斯顿,皮诺等). |

#### 字段图案

-   A 类 **点** (单位:千美元)`.`匹配子域.
    -   譬如说. `user.address.city` 音轨更改 `city` 内字段 `user.address`。 。 。 .
-   A 类 **美元数** 签名( e)`$`与“任何阵列索引”相匹配
    -   譬如说. `contacts.$.phone` 音轨更改 `phone` 字段为 **任意** 参数 `contacts` 阵列.

## 使用量

使用任何 Mongoose 插件 :

```js
const mongoose = require("mongoose");
const mongooseTracker = require("@expander/mongoose-tracker");

const { Schema } = mongoose.Schema;

const CarsSchema = new Schema({
  tags: [String],
  description: String,
  price: { type: Number, default: 0 },
});

CarsSchema.plugin(mongooseTracker, {
  limit: 50,
  name: "metaDescriptions",
  fieldsToTrack: ["price", "description"],
});

module.exports = mongoose.model("Cars", CarsSchema);
```

* * *

### 使用 `_changedBy` 记录更改

这个 `_changedBy` 字段允许跟踪对文档进行特定修改的人.  
您可以在更新文档前直接设置此字段.  
建议使用 **用户标识**,但任何字符串值都可以指定.

#### 示例

```js
async function foo() {
  // Create a new document
  const doc = await SomeModel.find({ name: "Initial Name" });
  doc.name = "New Name";
  // Set the user or system responsible for the creation
  doc._changedBy = "creator"; // Replace 'creator' with the user's ID or identifier
  await doc.save();
}
```

#### 正在生成历史日志

```js
[
  {
    action: "updated",
    at: 1734955271622,
    changedBy: "creator",
    changes: [
      {
        field: "name",
        before: "Initial Name",
        after: "New Name",
      },
    ],
  },
];
```

### 关键说明

-   changedBy字段是可选的,但高度推荐问责.
    
-   您可以根据当前用户的ID,用户名或其他独特的标识符,动态设置 changedBy.
    

* * *

## 《公约》的重要性 `_display` 外地

这个 `_display` 字段对于提高历史日志的可读性至关重要。 而不是用数组索引记录原始的字段路径(例如, `orders.0.items.1.price`,该插件将使用 `_display` 字段,以显示更有意义的标识符.

#### 如何运作

1.  **是否在场 `_display`数字 :**
    
    -   确保每个子文件(例如命令内的项目)包括a `_display` 字段.
    -   此字段应当包含一个唯一标识对象的字符串值,例如名称或可读标签.
2.  **连接机制 :**
    
    -   当跟踪字段更新时(例如, `orders.$.items.$.price`,插件检索 `_display` 相应的项目值.
    -   然后它会把这个调好 `_display` 与已更改的字段名称一起为历史日志构成可读字符串.
    -   **示例**
        -   **Raw 字段路径 :** `orders.0.items.1.price`
        -   **与 `_display`数字 :** `"Test Item 2 price"`
3.  **处理对象 :**
    
    -   如果 `_display` 字段包含一个 `ObjectId` 引用另一个文档, 插件会通过引用获取 `_display` 父文档的值.
    -   这种递归解析持续到获得字符串值,确保历史日志保持信息性.

#### 福利

-   **清晰度 :** 提供了清晰而简洁的变化表述,使人们更容易理解修改的内容.
-   **可读性 :** 避免从数组索引中产生混乱,特别是在有多个嵌入式数组的文档中.
-   **相关性:** 重点是在应用程序背景下具有重要意义的有意义的标识符.

## 示例

-   考虑以下方案:

```ts
interface Item extends Document {
  name: string;
  price: number;
  _display: string;
}

const ItemSchema = new Schema<Item>({
  name: { type: String, required: true },
  price: { type: Number, required: true },
  _display: { type: String, required: true },
});

interface Order extends Document {
  orderNumber: string;
  date: Date;
  items: Item[];
  _display:string;
}

const OrderSchema = new Schema<Order>({
  orderNumber: { type: String, required: true, unique: true },
  date: { type: Date, required: true, default: Date.now },
  items: { type: [ItemSchema], required: true },
  _display: { type: String },
});

interface PurchaseDemand extends Document {
  pdNumber: string;
  orders: Order[];
}

const PurchaseDemandSchema = new Schema<PurchaseDemand>({
  pdNumber: { type: String, required: true, unique: true },
  orders: [OrderSchema],
});

PurchaseDemandSchema.plugin(mongooseTracker, {
  fieldsToTrack: ["orders.$.date", "orders.$.items.$.price"], //The Fields I want to track.
});

const PurchaseDemandModel = mongoose.model<PurchaseDemand>(
  "PurchaseDemand",
  PurchaseDemandSchema
);
```

```js
const purchaseDemand = new PurchaseDemand({
  pdNumber: "PD-001",
  orders: [
    {
      orderNumber: "ORD-001",
      items: [
        { name: "Test Item 1", price: 100, _display: "Test Item 1" },
        { name: "Test Item 2", price: 200, _display: "Test Item 2" },
      ],
      _display: "Order 1",
    },
  ],
});


// Update an item's price
purchaseDemand._changedBy = 'system';
purchaseDemand.orders[0].items[1].price = 250;
await purchaseDemand.save();
```

#### 历史日志条目 :

```js
{
  "action": "updated",
  "at": 1734955271622,
  "changedBy": "system",
  "changes": [
    {
      "field": "Test Item 2 price", // instead of "orders.0.items.1.price" 
      "before": 200,
      "after": 250
    }
  ]
}
```

### 跟踪阵列元素中的嵌入物体

当跟踪数组元素内的嵌入对象时,插件会智能地解决 `_display` 从数组元素本身,而不是从嵌入对象。 这对有巢状结构的复杂计划特别有用.

#### 示例:追踪供应商尺寸

```typescript
const BusinessPartnerSchema = new Schema({
  name: { type: String, required: true },
  _display: { type: String, required: true }
});

const ExpanderProductSchema = new Schema({
  name: { type: String, required: true },
  availableSuppliers: [
    {
      name: { type: String, required: true },
      supplierId: {
        type: Schema.Types.ObjectId,
        ref: 'BusinessPartner',
        required: true
      },
      dimensions: {
        boxUnitLengthSide: { type: Number, default: 0 },
        boxUnitWidthSide: { type: Number, default: 0 },
        boxUnitHeightSide: { type: Number, default: 0 },
        boxUnitWeight: { type: Number, default: 0 }
      },
      cost: { type: Number, default: 0 },
      _display: {
        type: Schema.Types.ObjectId,
        ref: 'BusinessPartner'  // References BusinessPartner
      }
    }
  ]
});

// Track nested dimension fields
ExpanderProductSchema.plugin(mongooseTracker, {
  fieldsToTrack: [
    'availableSuppliers.$.dimensions.boxUnitLengthSide',
    'availableSuppliers.$.dimensions.boxUnitWidthSide',
    'availableSuppliers.$.dimensions.boxUnitHeightSide',
    'availableSuppliers.$.dimensions.boxUnitWeight'
  ]
});
```

#### 用法 :

```javascript
const supplier = await BusinessPartner.create({
  name: 'Xinlong Plastic Trunking Co Ltd',
  _display: 'Xinlong Plastic Trunking Co Ltd'
});

const product = await ExpanderProduct.create({
  name: 'Test Product',
  availableSuppliers: [{
    name: supplier.name,
    supplierId: supplier._id,
    dimensions: {
      boxUnitLengthSide: 10,
      boxUnitWidthSide: 20,
      boxUnitHeightSide: 30,
      boxUnitWeight: 5
    },
    cost: 50,
    _display: supplier._id  // ObjectId reference
  }]
});

// Update dimensions
product.availableSuppliers[0].dimensions.boxUnitLengthSide = 15;
product.availableSuppliers[0].dimensions.boxUnitWeight = 7;
await product.save();
```

#### 历史日志条目 :

```javascript
{
  "action": "updated",
  "at": 1734955271622,
  "changedBy": null,
  "changes": [
    {
      "field": "Xinlong Plastic Trunking Co Ltd boxUnitLengthSide",  // Resolved from BusinessPartner
      "before": 10,
      "after": 15
    },
    {
      "field": "Xinlong Plastic Trunking Co Ltd boxUnitWeight",  // Resolved from BusinessPartner
      "before": 5,
      "after": 7
    }
  ]
}
```

**说明:** 插件解决 `_display` 从 `availableSuppliers[0]._display` 而不是来自 `availableSuppliers[0].dimensions._display`这提供了有意义的背景,表明哪些供应商的维度被修改了.

* * *

## 日志

插件包括内置的日志系统来帮助调试和监测. 您可以使用 `logLevel` 选项或提供自定义日志.

### 使用内建登录

```js
YourSchema.plugin(mongooseTracker, {
  name: "history",
  fieldsToTrack: ["title", "status"],
  logLevel: 'info' // Set log level
});
```

**可用的日志级别 :**

-   `'debug'` - 调试的详细信息(实地变化、阵列操作、参考文献)
-   `'info'` - 一般性信息信息(提示、历史更新)
-   `'warn'` - 警告信息(丢失文件,无效引用)
-   `'error'` - 错误消息(无效模式、搜索失败)
-   `'none'` - 禁用所有记录( 默认)

### 日志输出示例

```bash
# Info level
[mongoose-tracker] [INFO] Initializing mongoose-tracker plugin with options: { ... }
[mongoose-tracker] [INFO] Pre-save hook triggered for document 507f1f77bcf86cd799439011

# Debug level (includes all info + detailed tracking)
[mongoose-tracker] [DEBUG] Tracking changes for path: title, displayField: title
[mongoose-tracker] [DEBUG] Primitive value changed for title: "Old Title" => "New Title"
[mongoose-tracker] [DEBUG] Array elements added to orders: 2

# Warn level
[mongoose-tracker] [WARN] Referenced document not found for model: Category, id: 507f1f77bcf86cd799439012
```

### 使用自定义记录器

您可以通过执行该程序提供自己的记录器(例如Winston, Pino) `Logger` 接口 :

```js
import winston from 'winston';

const customLogger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'mongoose-tracker.log' })
  ]
});

// Adapt Winston to mongoose-tracker Logger interface
const loggerAdapter = {
  debug: (message, ...args) => customLogger.debug(message, args),
  info: (message, ...args) => customLogger.info(message, args),
  warn: (message, ...args) => customLogger.warn(message, args),
  error: (message, ...args) => customLogger.error(message, args)
};

YourSchema.plugin(mongooseTracker, {
  name: "history",
  fieldsToTrack: ["title"],
  logger: loggerAdapter
});
```

### 使用皮诺

```js
import pino from 'pino';

const pinoLogger = pino({
  level: 'debug',
  transport: {
    target: 'pino-pretty'
  }
});

const loggerAdapter = {
  debug: (message, ...args) => pinoLogger.debug({ args }, message),
  info: (message, ...args) => pinoLogger.info({ args }, message),
  warn: (message, ...args) => pinoLogger.warn({ args }, message),
  error: (message, ...args) => pinoLogger.error({ args }, message)
};

YourSchema.plugin(mongooseTracker, {
  name: "history",
  logger: loggerAdapter
});
```

## 跟踪阵列字段

当指定字段 ToTrack 中的数组字段时, 如“ 顺序 ”, **巨鹅追踪器** 将监视该数组内的任何增删。 这意味着:

-   **增加数**: 当新元素被添加到数组中时, 插件会记录历史数组中的这个变化 .
-   **删除**: 当一个已有元素从数组中去除时, 插件会记录历史数组中的这个去除 .

### 有引用的矩阵元素 `_display`

**巨鹅追踪器** 也支持跟踪数组 `_display` 字段是一个 `ObjectId` 参考另一种模式。 插件将自动解析引用并使用引用文档的 `_display` 历史日志中的值.

#### 示例:跟踪供应商阵列

```ts
const BusinessPartnerSchema = new Schema({
  name: { type: String, required: true },
  type: { type: String },
  _display: { type: String, required: true }
});

const ExpanderProductSchema = new Schema({
  name: { type: String, required: true },
  availableSuppliers: [
    {
      name: { type: String, required: true },
      supplierId: {
        type: Schema.Types.ObjectId,
        ref: 'BusinessPartner',
        required: true
      },
      cost: { type: Number, default: 0 },
      // _display references the BusinessPartner document
      _display: {
        type: Schema.Types.ObjectId,
        ref: 'BusinessPartner'
      }
    }
  ]
});

// Track changes to availableSuppliers array
ExpanderProductSchema.plugin(mongooseTracker, {
  fieldsToTrack: ['availableSuppliers']
});

const BusinessPartner = mongoose.model('BusinessPartner', BusinessPartnerSchema);
const ExpanderProduct = mongoose.model('ExpanderProduct', ExpanderProductSchema);
```

#### 添加供应商 :

```js
const supplier = await BusinessPartner.create({
  name: 'Supplier A',
  type: 'manufacturer',
  _display: 'Supplier A Display'
});

const product = await ExpanderProduct.findOne({ name: 'My Product' });

product.availableSuppliers.push({
  name: supplier.name,
  supplierId: supplier._id,
  cost: 100,
  _display: supplier._id  // ObjectId reference
});

await product.save();
```

#### 历史日志条目 :

```js
{
  "action": "added",
  "at": 1734955271622,
  "changedBy": null,
  "changes": [
    {
      "field": "availableSuppliers",
      "before": null,
      "after": "Supplier A Display"  // Resolved from BusinessPartner._display
    }
  ]
}
```

#### 删除供应商 :

```js
product.availableSuppliers = product.availableSuppliers.filter(
  s => s.supplierId.toString() !== supplier._id.toString()
);

await product.save();
```

#### 历史日志条目 :

```js
{
  "action": "removed",
  "at": 1734955271622,
  "changedBy": null,
  "changes": [
    {
      "field": "availableSuppliers",
      "before": "Supplier A Display",  // Resolved from BusinessPartner._display
      "after": null
    }
  ]
}
```

* * *

#### 操作 :

添加元素( 命令) :

```js

PurchaseDemandSchema.plugin(mongooseTracker, {
  fieldsToTrack: ["orders"],
});


const purchaseDemand = await PurchaseDemandModel.create({
  pdNumber: "PD-TEST-002",
  orders: [],
});

// Adding a new order
purchaseDemand.orders.push({
  orderNumber: "ORD-TEST-002",
  date: new Date(),
  items: [{ name: "Test Item 3", price: 300, _display: "Test Item 3" }],
  _display: "ORD-TEST-002",
});

await purchaseDemand.save();
```

#### 历史日志条目添加后 :

```js
{
  "action": "added",
  "at": 1734955271622,
  "changedBy": null,
  "changes": [
    {
      "field": "orders",
      "before": null,
      "after": 'ORD-TEST-002' // the name of _display.
    }
  ]
}

```

#### 删除元素( 命令) :

```js
purchaseDemand.orders.pop(); // we remove the last element that insert in orders. (ORD-TEST-002)
await purchaseDemand.save();
```

#### 删除后的历史日志条目 :

```js
{
  "action": "removed",
  "at": 1734955271622,
  "changedBy": null,
  "changes": [
    {
      "field": "orders",
      "before": 'ORD-TEST-002'
      "after": null
    }
  ]
}

```

## 捐款

-   使用 Eslint 插入您的代码 .
-   为任何新的或已更改的功能添加测试 .
-   如果添加或更改任何功能,则用示例更新读取器.

## 法律

-   作者:罗尼·杰克·维图利
-   许可证: Apache-2.0

## 常见问题

### @expander/mongoose-tracker 是什么？

是一个 mongoose 插件, 它会自动跟踪文档创建、 更新和可选修改部分字段的时间

### 如何安装 @expander/mongoose-tracker？

在项目目录运行 npm install @expander/mongoose-tracker，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：mongoose（^6\.1\.5）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @expander/mongoose-tracker 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @expander/mongoose-tracker 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @expander/mongoose-tracker 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @expander/mongoose-tracker 可以商用吗？

@expander/mongoose-tracker 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @expander/mongoose-tracker 的下载量有多少？

根据 npm 官方下载统计，@expander/mongoose-tracker 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,105 次，日均约 70 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @expander/mongoose-tracker 还在维护吗？

最新版本 1\.8\.2 发布于 2026/01/13（9 个月前）；至今共发布 20 个版本，其中过去 12 个月发布了 3 个；首次发布于 2024/12/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

