MongoDB Academy · 课时

索引属性:唯一、稀疏、部分和 TTL

您将创建具有唯一、稀疏、部分和 TTL 属性的专用索引,以强制执行约束并自动清理数据。

第 3 / 4 课13 个步骤

索引属性:唯一、稀疏、部分和 TTL 是 CoddyKit 上的免费 MongoDB Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 MongoDB Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 MongoDB Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Index Properties Overview

Beyond the basic B-tree structure, MongoDB indexes support several property modifiers that change how they behave: unique enforces distinctness, sparse skips null entries, partial limits the index to a subset of documents, and TTL automatically expires documents. Each property is set in the options object of createIndex() and serves a specific purpose in production schemas.

Unique Indexes

A unique index guarantees that no two documents in the collection can have the same value for the indexed field. Any insert or update that would produce a duplicate triggers a DuplicateKey error. Unique indexes are commonly used on fields like email, username, or any natural key. The _id index is always unique.

// Unique index on email
db.users.createIndex(
  { email: 1 },
  { unique: true }
);

// First insert succeeds
db.users.insertOne({ email: 'alice@example.com', name: 'Alice' });

// Second insert with same email throws E11000 DuplicateKey
db.users.insertOne({ email: 'alice@example.com', name: 'Bob' });

Unique Compound Indexes

Unique constraints can span multiple fields in a compound index. The uniqueness check applies to the combination of the indexed fields, not each field individually. This is perfect for modelling relationships like 'a user can only follow another user once' without a separate lookup query.

// A user can only 'follow' each other user once
db.follows.createIndex(
  { followerId: 1, followingId: 1 },
  { unique: true }
);

// This succeeds
db.follows.insertOne({ followerId: 'u1', followingId: 'u2' });

// This fails - same pair already exists
db.follows.insertOne({ followerId: 'u1', followingId: 'u2' });

Sparse Indexes

By default, a MongoDB index includes entries for every document, even those where the indexed field is missing (stored as null). A sparse index only includes documents that have the indexed field. This is useful for optional fields that appear in only a small subset of documents—without sparse, every null/missing document would bloat the index unnecessarily.

// Only documents WITH a phoneNumber are indexed
db.users.createIndex(
  { phoneNumber: 1 },
  { sparse: true }
);

// This document is NOT in the index (phoneNumber absent)
db.users.insertOne({ name: 'Alice', email: 'a@b.com' });

// This document IS in the index
db.users.insertOne({ name: 'Bob', phoneNumber: '+1555000' });

Sparse Unique: Optional Unique Fields

Combining sparse: true with unique: true lets you create a unique constraint on an optional field. Without sparse, a unique index would only allow one document to omit the field (since all missing values would be stored as null and null must be unique). Sparse + unique means: if the field exists, it must be distinct; if it's missing, the document is simply excluded from the index.

// Optional unique twitterHandle
db.users.createIndex(
  { twitterHandle: 1 },
  { unique: true, sparse: true }
);

// Multiple users without twitterHandle are all allowed
db.users.insertMany([
  { name: 'Alice' },
  { name: 'Bob' },
  { name: 'Carol', twitterHandle: '@carol' }
]);

Partial Indexes

A partial index indexes only the documents that match a partialFilterExpression. This is more flexible than sparse (which only checks for field existence) because you can specify any filter condition. Partial indexes are smaller and faster to maintain than full indexes when a query always includes a predictable filter on the collection.

// Only index orders that are 'active' - skips completed/cancelled
db.orders.createIndex(
  { userId: 1, createdAt: -1 },
  {
    partialFilterExpression: { status: 'active' },
    name: 'idx_orders_active'
  }
);

// This query hits the partial index because it includes status:active
db.orders.find({ userId: 'u1', status: 'active' })
  .sort({ createdAt: -1 });

Partial Index Query Requirements

MongoDB can use a partial index only when the query guarantees that it requests a subset of the documents covered by the index. In practice, this means your query filter must include the same condition as the partialFilterExpression. Queries that don't include this condition will fall back to a collection scan or another index because the partial index might be missing matching documents.

// Partial index only covers status: 'active'

// USES the partial index (filter includes status: 'active')
db.orders.find({ userId: 'u1', status: 'active' });

// DOES NOT USE the partial index (query might return completed orders)
db.orders.find({ userId: 'u1' });
// MongoDB must use full scan or a different index here

TTL Indexes: Automatic Expiry

A TTL (Time-To-Live) index is a special single-field index on a date field that tells MongoDB to automatically delete documents after a specified number of seconds. A background thread runs every 60 seconds and removes expired documents. TTL indexes are perfect for session data, cache entries, audit logs, and any data with a natural shelf life.

// Automatically delete sessions 24 hours after 'createdAt'
db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 86400 } // 86400 = 24 * 60 * 60
);

// Insert a session - it will auto-delete after 24h
db.sessions.insertOne({
  userId: 'u1',
  token: 'abc123',
  createdAt: new Date()
});

TTL on a Specific Expiry Field

Instead of a fixed duration from creation, you can set expireAfterSeconds: 0 and store the exact expiry timestamp in the indexed date field. MongoDB will delete each document at the moment the stored date passes. This gives you per-document control over expiry, useful for subscription end dates, JWT token expiry, or scheduled job cleanup.

// Delete each document at its own 'expiresAt' time
db.tokens.createIndex(
  { expiresAt: 1 },
  { expireAfterSeconds: 0 }
);

// This token expires in 1 hour
const oneHourFromNow = new Date(Date.now() + 3600 * 1000);
db.tokens.insertOne({
  userId: 'u1',
  value: 'tok_xyz',
  expiresAt: oneHourFromNow
});

TTL Limitations to Know

TTL indexes have a few important restrictions: the indexed field must be a BSON date (not a string); TTL indexes cannot be compound; the background cleanup thread runs approximately every 60 seconds so there is a small delay between expiry time and actual deletion; and TTL indexes do not apply to capped collections. The 60-second delay is usually acceptable but matters for high-precision use cases.

// TTL only works on ISODate fields, not strings
// WRONG - will NOT expire:
db.logs.insertOne({ ts: '2024-01-01T00:00:00Z' });

// CORRECT - will expire:
db.logs.insertOne({ ts: new Date('2024-01-01T00:00:00Z') });

// Also, TTL cannot be compound:
// This is INVALID:
db.logs.createIndex({ ts: 1, userId: 1 }, { expireAfterSeconds: 3600 });

Choosing the Right Index Property

Use unique to enforce natural keys and prevent duplicates. Use sparse when a field is optional and present in only a minority of documents. Use partial when queries always include a known filter condition and you want a leaner index. Use TTL to automate data expiry without application-level cron jobs. These properties can be combined: unique + sparse is common for optional unique identifiers.

// Summary of all four property types

// Unique
db.users.createIndex({ email: 1 }, { unique: true });

// Sparse
db.users.createIndex({ phone: 1 }, { sparse: true });

// Partial
db.orders.createIndex({ userId: 1 }, { partialFilterExpression: { status: 'pending' } });

// TTL
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 });

Quick Check

Test your understanding of MongoDB index properties from this lesson.

Lesson Recap

In this lesson you learned: unique indexes enforce distinctness on one or multiple fields, sparse indexes skip documents that lack the indexed field, partial indexes index only documents matching a filter expression, and TTL indexes automatically delete expired documents. Next up we learn to read explain() output to diagnose slow queries.

免费开始

用 AI 导师学习 JavaScript — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
30
课程
120

常见问题解答

「索引属性:唯一、稀疏、部分和 TTL」课时是免费的吗?

是的 — 「索引属性:唯一、稀疏、部分和 TTL」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 MongoDB Academy 课程的其余内容,请升级到 CoddyKit PRO。 MongoDB Academy 课程共包含 4 节课。

「索引属性:唯一、稀疏、部分和 TTL」这节课中我会学到什么?

您将创建具有唯一、稀疏、部分和 TTL 属性的专用索引,以强制执行约束并自动清理数据。 你通过在浏览器中直接运行的动手代码来练习 MongoDB Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 MongoDB Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 MongoDB Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「索引属性:唯一、稀疏、部分和 TTL」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 MongoDB Academy 课中编写并运行代码吗?

能。每节 MongoDB Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. MongoDB B 树索引的工作原理
  2. 创建单字段索引和复合索引
  3. 索引属性:唯一、稀疏、部分和 TTL
  4. 读取 explain() 输出以诊断查询
← 返回 MongoDB Academy