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
相关推荐
lazy H15 分钟前
【计算机网络】第 2 篇:一条数据如何穿过网络?彻底理解数据封装与解封装
网络·经验分享·后端·学习·计算机网络
我命由我1234523 分钟前
软件工程概念 - 可插拔性
java·后端·学习·java-ee·系统架构·软件工程·学习方法
Bazingga28 分钟前
RAG路由全景:一个问题走到岔路口,谁来指路
后端
云边有个稻草人31 分钟前
从日志到落库:数据集成产品 KFS 如何打通异构数据库实时同步链路
后端
努力小陈137 分钟前
从 Java 到 Go:后端工程师的 30 分钟语法速查
后端
Thneonl37 分钟前
一个 502,十种病因:nginx 反代排障分诊树
后端·架构
花间相见38 分钟前
【计算基础|MySQL09】索引(下):失效与设计
数据库·后端·面试
南丘山43 分钟前
接口自动化测试从零搭:31 条用例跑 4 秒,抓出 6 个权限缺陷
后端
掘金小豆1 小时前
Spring AI 实战:从一次可运行的模型调用到 RAG 体系
后端·程序员·ai编程
前端小万1 小时前
探索副业五个月,最终以放弃告终
前端·后端·面试