MongoDB 项目嵌套字段

Mehvish Ashiq 2023年1月30日
  1. MongoDB 项目嵌套字段
  2. 使用 $project 聚合阶段在 MongoDB 中投影嵌套字段
  3. 使用 $unset 聚合阶段获取 MongoDB 中排除指定字段的嵌套字段
  4. 使用 forEach() 循环在 MongoDB 中获取嵌套字段
  5. 使用 mapReduce() 方法在 MongoDB 中投影嵌套字段
MongoDB 项目嵌套字段

今天,我们将学习如何使用 $project$unset 聚合阶段、forEach() 循环和 mapReduce() 方法在 MongoDB 中查询数据时投影嵌套字段。

MongoDB 项目嵌套字段

在 MongoDB 中,我们可以使用 find() 方法检索所有文档,但如果我们只想访问特定的嵌套字段怎么办。这就是我们使用投影的地方。

我们可以通过各种方式投影嵌套字段。在这里,我们将了解以下项目嵌套字段的解决方案。

  1. 使用 $project 聚合阶段
  2. 使用 $unset 聚合阶段
  3. 使用 forEach() 循环
  4. 使用 mapReduce() 函数

为了学习上述方法,让我们创建一个名为 nested 的集合,其中包含一个文档。你也可以使用下面给出的查询与我们联系。

示例代码:

// MongoDB version 5.0.8

> db.nested.insertOne(
    {
        "name": {
            "first_name": "Mehvish",
            "last_name": "Ashiq",
         },
         "contact": {
            "phone":{"type": "manager", "number": "123456"},
            "email":{ "type": "office", "mail": "delfstack@example.com"}
         },
         "country_name" : "Australien",
         "posting_locations" : [
             {
                 "city_id" : 19398,
                 "city_name" : "Bondi Beach (Sydney)"
             },
             {
                  "city_id" : 31101,
                  "city_name" : "Rushcutters Bay (Sydney)"
             },
             {
                  "city_id" : 31022,
                  "city_name" : "Wolly Creek (Sydney)"
             }
          ],
          "regions" : {
              "region_id" : 796,
              "region_name" : "Australien: New South Wales (Sydney)"
          }
    }
);

使用 db.nested.find().pretty(); 在 mongo shell 上查看插入的数据。

使用 $project 聚合阶段在 MongoDB 中投影嵌套字段

示例代码:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> var project = {};
> project["id"] = "$"+current_location+".city_id";
> project["name"] = "$"+current_location+".city_name";
> project["regions"] = 1;

> var find = {};
> find[current_location] = {"$exists":true};

> db.nested.aggregate([
    { $match : find },
    { $project : project }
]).pretty()

输出:

{
        "_id" : ObjectId("62a96d397c7e3688aea26d0d"),
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "id" : [
                19398,
                31101,
                31022
        ],
        "name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

在这里,我们将名为 posting_locations 的第一级字段保存在名为 current_location 的变量中。

然后,我们使用该变量访问 city_idcity_name 并将它们保存在 project 对象中,同时使用括号表示法为 project 对象创建属性。此外,我们将 regions 字段保存在 project["regions"] 中。

接下来,我们有另一个名为 find 的对象,我们将在 aggregate() 方法中使用它来匹配文档。在 aggregate() 方法中,我们使用 $match 阶段来匹配文档,并使用 $project 来投影字段,无论是嵌套的还是第一级的。

我们使用 $project 来指定要在输出中显示的字段。如果我们只想在没有任何过滤查询的情况下投影指定的嵌套字段,我们可以使用以下解决方案。

示例代码:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> db.nested.aggregate({
    $project: {
         "_id": 0,
         "city_id": "$" + current_location + ".city_id",
         "city_name": "$" + current_location + ".city_name",
         "regions": 1
    }
}).pretty();

输出:

{
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "city_id" : [
                19398,
                31101,
                31022
        ],
        "city_name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

使用 $unset 聚合阶段获取 MongoDB 中排除指定字段的嵌套字段

示例代码:

// MongoDB version 5.0.8

> db.nested.aggregate({
        $unset: ["posting_locations.city_id", "contact", "regions", "name", "_id"]
}).pretty()

输出:

{
        "country_name" : "Australien",
        "posting_locations" : [
                {
                        "city_name" : "Bondi Beach (Sydney)"
                },
                {
                        "city_name": "Rushcutters Bay (Sydney)"
                },
                {
                        "city_name": "Wolly Creek (Sydney)"
                }
        ]
}

在这里,我们使用 $unset 运算符,用于删除指定的字段或字段数组。

请记住,我们使用点符号来指定嵌入的文档或文档数组。如果给定字段不存在,$unset 运算符不执行任何操作。

当我们使用 $ 匹配数组的元素时,$unset 运算符将匹配的元素替换为 null 而不是从数组中删除它们。此行为有助于保持元素位置和数组大小一致。

使用 forEach() 循环在 MongoDB 中获取嵌套字段

示例代码:

// MongoDB version 5.0.8

> var bulk = db.newcollection.initializeUnorderedBulkOp(),
   counter = 0;

> db.nested.find().forEach(function(doc) {
    var document = {};
    document["name"] = doc.name.first_name + " " + doc.name.last_name;
    document["phone"] = doc.contact.phone.number;
    document["mail"] = doc.contact.email.mail;
    bulk.insert(document);
    counter++;
    if (counter % 1000 == 0) {
        bulk.execute();
        bulk = db.newcollection.initializeUnorderedBulkOp();
    }
});

> if (counter % 1000 != 0) { bulk.execute(); }

你将看到类似于以下内容的内容。

BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 1,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})

接下来,在你的 mongo shell 上执行以下命令以查看投影字段。

// MongoDB version 5.0.8

> db.newcollection.find().pretty();

输出:

{
        "_id" : ObjectId("62a96f2d7c7e3688aea26d0e"),
        "name" : "Mehvish Ashiq",
        "phone" : "123456",
        "mail" : "delfstack@example.com"
}

为了学习这个示例代码,假设我们想要获取某些嵌套字段并将它们插入到一个新集合中。在这里,将转换后的字段作为文档插入到新集合中可能会根据 nested 集合的大小影响我们的操作。

我们可以通过使用新的无序 bulk insert API 来避免这种缓慢的插入性能。它将通过批量发送来简化插入操作,并实时向我们反馈操作是成功还是失败。

因此,我们使用 bulk insert API 将所需的数据结构插入 newcollection 集合中,其中全新的文档将使用 nested 集合游标的 forEach() 循环创建。要创建新属性,我们使用括号表示法

对于此代码,我们假设有大量数据。因此,我们将把操作以 1000 的批次发送到服务器以执行批量插入操作。

结果,它为我们提供了良好的性能,因为我们不是向服务器发送每个请求,而是每 1000 个请求发送一次。

使用 mapReduce() 方法在 MongoDB 中投影嵌套字段

示例代码:

// MongoDB version 5.0.8

> function map() {
    for(var i in this.posting_locations) {
         emit({
             "country_id" : this.country_id,
             "city_id" : this.posting_locations[i].city_id,
             "region_id" : this.regions.region_id
         },1);
    }
}

> function reduce(id,docs) {
      return Array.sum(docs);
}

> db.nested.mapReduce(map,reduce,{ out : "map_reduce_output" } )

现在,运行以下查询以查看输出。

// MongoDB version 5.0.8
> db.map_reduce_output.find().pretty();

输出:

{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 19398,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31022,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31101,
                "region_id" : 796
        },
        "value" : 1
}

对于这个示例代码,我们使用 mapReduce() 函数对 nested 集合的所有文档执行 map-reduce。为此,我们必须遵循下面简要说明的三步过程。

  • 定义 map() 函数来处理每个输入文档。在这个函数中,this 关键字是指正在由 map-reduce 操作处理的当前文档,emit() 函数将给定的值映射到键并返回它们。
  • 在这里,我们定义了相应的 reduce() 函数,这是发生数据聚合的实际位置。它需要两个参数(keysvalues);我们的代码示例采用 iddocs

    请记住,docs 的元素是由 map() 方法中的 emit() 函数返回的。在这一步,reduce() 函数将 docs 数组缩减为其值(元素)的总和。

  • 最后,我们使用 map()reduce() 函数对 nested 集合中的所有文档执行 map-reduce。我们使用 out 将输出保存在指定的集合中,在本例中为 map_reduce_output
作者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook