MongoDB(42)如何使用$project阶段?

在MongoDB中,使用 $project 阶段可以重塑每个文档的结构,类似于SQL中的 SELECT 子句。你可以使用 $project 来包括或排除字段、创建新的字段、重命名字段,甚至执行一些简单的运算。

使用 $project 阶段的基本结构

javascript 复制代码
{
  $project: {
    <field1>: <expression1>,
    <field2>: <expression2>,
    // 其他字段
  }
}
  • <field> 是你想要包含在输出文档中的字段名称。
  • <expression> 是一个包括或排除字段的布尔值、算术操作、字符串操作、日期操作等。

代码示例

以下是使用Node.js进行投影操作的详细示例。首先确保安装了MongoDB的Node.js驱动:

bash 复制代码
npm install mongodb

插入示例数据

javascript 复制代码
const { MongoClient } = require('mongodb');

async function insertData() {
    const uri = "mongodb://localhost:27017";
    const client = new MongoClient(uri, { useUnifiedTopology: true });

    try {
        await client.connect();
        const db = client.db('myDatabase');
        const collection = db.collection('orders');

        await collection.deleteMany({}); // 清空集合

        await collection.insertMany([
            { customerId: 1, amount: 100, status: "shipped", date: new Date("2021-01-01") },
            { customerId: 1, amount: 200, status: "pending", date: new Date("2021-02-01") },
            { customerId: 2, amount: 150, status: "shipped", date: new Date("2021-03-01") },
            { customerId: 2, amount: 50, status: "pending", date: new Date("2021-04-01") },
            { customerId: 3, amount: 250, status: "shipped", date: new Date("2021-05-01") }
        ]);

        console.log("Data inserted");
    } finally {
        await client.close();
    }
}

insertData().catch(console.error);

使用 $project 进行投影

javascript 复制代码
async function aggregateData() {
    const uri = "mongodb://localhost:27017";
    const client = new MongoClient(uri, { useUnifiedTopology: true });

    try {
        await client.connect();
        const db = client.db('myDatabase');
        const collection = db.collection('orders');

        // 使用 $project 选择特定字段
        console.log("\n$project stage (select specific fields):");
        let result = await collection.aggregate([
            {
              $project: {
                _id: 0,  // 不包括 _id 字段
                customerId: 1,  // 包括 customerId 字段
                amount: 1,  // 包括 amount 字段
                status: 1  // 包括 status 字段
              }
            }
        ]).toArray();
        console.log(result);

        // 使用 $project 创建新的字段
        console.log("\n$project stage (create new fields):");
        result = await collection.aggregate([
            {
              $project: {
                customerId: 1,
                amount: 1,
                status: 1,
                amountWithTax: { $multiply: ["$amount", 1.1] }  // 创建新的字段 amountWithTax,值为 amount 的 1.1 倍
              }
            }
        ]).toArray();
        console.log(result);

        // 使用 $project 重命名字段
        console.log("\n$project stage (rename fields):");
        result = await collection.aggregate([
            {
              $project: {
                _id: 0,
                customer: "$customerId",  // 将 customerId 字段重命名为 customer
                total: "$amount",  // 将 amount 字段重命名为 total
                status: 1,
                date: 1
              }
            }
        ]).toArray();
        console.log(result);

        // 使用 $project 包含计算字段
        console.log("\n$project stage (include calculated fields):");
        result = await collection.aggregate([
            {
              $project: {
                customerId: 1,
                amount: 1,
                status: 1,
                year: { $year: "$date" },  // 包括 year 字段,值为 date 字段的年份
                month: { $month: "$date" }  // 包括 month 字段,值为 date 字段的月份
              }
            }
        ]).toArray();
        console.log(result);

    } finally {
        await client.close();
    }
}

aggregateData().catch(console.error);

在这个示例中,我们演示了如何使用 $project 阶段进行投影操作:

  1. 选择特定字段
  2. 创建新的字段
  3. 重命名字段
  4. 包含计算字段

运行这个脚本后,你会得到如下结果(示例输出):

javascript 复制代码
// select specific fields 结果
$project stage (select specific fields):
[
  { customerId: 1, amount: 100, status: 'shipped' },
  { customerId: 1, amount: 200, status: 'pending' },
  { customerId: 2, amount: 150, status: 'shipped' },
  { customerId: 2, amount: 50, status: 'pending' },
  { customerId: 3, amount: 250, status: 'shipped' }
]

// create new fields 结果
$project stage (create new fields):
[
  { customerId: 1, amount: 100, status: 'shipped', amountWithTax: 110 },
  { customerId: 1, amount: 200, status: 'pending', amountWithTax: 220 },
  { customerId: 2, amount: 150, status: 'shipped', amountWithTax: 165 },
  { customerId: 2, amount: 50, status: 'pending', amountWithTax: 55 },
  { customerId: 3, amount: 250, status: 'shipped', amountWithTax: 275 }
]

// rename fields 结果
$project stage (rename fields):
[
  { customer: 1, total: 100, status: 'shipped', date: 2021-01-01T00:00:00.000Z },
  { customer: 1, total: 200, status: 'pending', date: 2021-02-01T00:00:00.000Z },
  { customer: 2, total: 150, status: 'shipped', date: 2021-03-01T00:00:00.000Z },
  { customer: 2, total: 50, status: 'pending', date: 2021-04-01T00:00:00.000Z },
  { customer: 3, total: 250, status: 'shipped', date: 2021-05-01T00:00:00.000Z }
]

// include calculated fields 结果
$project stage (include calculated fields):
[
  { customerId: 1, amount: 100, status: 'shipped', year: 2021, month: 1 },
  { customerId: 1, amount: 200, status: 'pending', year: 2021, month: 2 },
  { customerId: 2, amount: 150, status: 'shipped', year: 2021, month: 3 },
  { customerId: 2, amount: 50, status: 'pending', year: 2021, month: 4 },
  { customerId: 3, amount: 250, status: 'shipped', year: 2021, month: 5 }
]

其他语言示例

类似的投影操作也可以在其他编程语言中实现,如Python。以下是Python的示例代码:

安装PyMongo

在终端中运行以下命令来安装PyMongo:

bash 复制代码
pip install pymongo

使用Python进行投影

python 复制代码
from pymongo import MongoClient

def main():
    client = MongoClient('mongodb://localhost:27017/')
    db = client['myDatabase']
    collection = db['orders']

    # 使用 $project 选择特定字段
    print("\n$project stage (select specific fields):")
    pipeline = [
        {
          '$project': {
            '_id': 0,  # 不包括 _id 字段
            'customerId': 1,  # 包括 customerId 字段
            'amount': 1,  # 包括 amount 字段
            'status': 1  # 包括 status 字段
          }
        }
    ]
    result = list(collection.aggregate(pipeline))
    for doc in result:
        print(doc)

    # 使用 $project 创建新的字段
    print("\n$project stage (create new fields):")
    pipeline = [
        {
          '$project': {
            'customerId': 1,
            'amount': 1,
            'status': 1,
            'amountWithTax': { '$multiply': ["$amount", 1.1] }  # 创建新的字段 amountWith
相关推荐
gelald20 小时前
Spring - 循环依赖
java·后端·spring
JavaGuide20 小时前
万字详解 RAG 基础概念:什么是 RAG? 为什么需要?工作原理是?
后端·ai编程
希望永不加班20 小时前
SpringBoot 多数据源配置(读写分离基础)
java·spring boot·后端·spring
Java成神之路-20 小时前
Spring AOP 核心进阶:切入点表达式 + 通知类型 + 环绕通知避坑指南(Spring系列8)
java·后端·spring
清汤饺子20 小时前
Cursor + Claude Code 组合使用心得:我为什么不只用一个 AI 编程工具
前端·javascript·后端
无责任此方_修行中21 小时前
Redis 的"三面"人生:开源世界的权力转移
redis·后端·程序员
写Cpp的小黑黑21 小时前
时间同步(无需NTP):以time.is网站为例
后端
木子欢儿21 小时前
在 Fedora 上配置 Go 语言(Golang)开发环境
开发语言·后端·golang
coNh OOSI1 天前
Spring Boot问题总结
java·spring boot·后端