我是Mongo的新手(优先考虑SQL人员),并且在其他人设置的应用程序中工作。我有这样的记录,还有更多信息:
City:
name: "name"
State: ObjectId({id here})
slug: "slug"
images: [images]
...
状态还有一个带有slug的文本字段。我想为相关城市的城市创建一个新条目。因此它将是一个包含图像,slug,状态slug和名称的数组。我尝试了以下内容,但最终得到了stateSlug的查询信息:
db.getCollection('city').find(
{
$or:
[
{"name": "Camden"},
{"name": "Virginia Beach"},
{"name": "Annapolis"}
]
},{images:1, slug:1, state:1, name:1}
).forEach(function(city){
db.city.update({"name" : "Lewes"}, {$push:{'relatedCities':
{ "images":city.images,
"slug":city.slug,
"name":city.name,
"stateSlug":db.state.find(city.state,{slug:1,_id:0})
}
}})
})
有没有办法让这个查询有效?我有一个用于excel文件中的查询的名称和一个python脚本,它可以将这种格式的信息输出到js文件,如果我能弄清楚如何使它工作。谢谢你的帮助!
答案 0 :(得分:1)
您需要采取的方法涉及运行使用以下管道步骤的聚合管道(按给定的顺序):
1) $match
来过滤进入管道的文档。如果您的表达式涉及$in
,请考虑使用 $or
运算符代替 equality checks for the value of the same field 。这类似于SQL的WHERE
子句,例如
SELECT name, images, state, slug
WHERE name in ('Camden', 'Virginia Beach', 'Annapolis')
而不是
SELECT name, images, state, slug
WHERE
(name = 'Camden') OR
(name = 'Virginia Beach') OR
(name = 'Annapolis')
2) $lookup
对同一数据库中的非整数集合执行左外连接,以过滤来自“已加入”集合的文档,即state
集合用于处理。 $lookup
阶段会将输入文档中的state
字段与“已加入”集合状态的文档中的_id
字段进行相等匹配。< / p>
3) $unwind
- 上一个 $lookup
管道结果中的新字段是一个数组,因此您需要添加您的管道的 $unwind
阶段,以便您可以将数组展平,因为它需要作为非规范化字段进一步处理。
4) $group
管道步骤将所有文档分组并创建一个包含前一个管道字段的数组相关城市。 $group
管道运算符类似于SQL的GROUP BY
子句。在SQL中,除非使用任何聚合函数,否则不能使用GROUP BY
。同样,您也必须在MongoDB中使用聚合函数。您可以阅读有关聚合函数here的更多信息。
您需要创建数组的累加器运算符是 $push
。
5) $project
最后阶段用于从前面的管道中的文档中选择或重命名属性 - 类似于您对SQL SELECT
子句的处理方式。要使用字符串文字创建新字段,您需要 $literal
运算符,该运算符类似于SQL的AS
或ALIAS
关键字。
这里需要注意的一点是,在执行管道时,MongoDB会将运营商相互管道化。这里的“管道”采用Linux的含义:运算符的输出成为以下运算符的输入。每个运算符的结果是一个新的文档集合。所以Mongo按如下方式执行上述管道:
collection | $match | $lookup | $unwind | $group | $project => result
现在,当您在mongo shell中运行此聚合管道时,结果将是您在 {{3}上使用 toArray()
方法时获得的数组通过调用city
集合上的 cursor
方法返回。
然后,您可以通过首先通过零索引访问结果数组中的唯一元素来创建city
集合中的新城市条目,该零索引是具有聚合字段的新city
文档,并且使用城市集合上的 aggregate()
方法来保留文档。
以下示例演示了上述概念:
var pipeline = [
{
"$match": {
"name": { "$in": ["Camden", "Virginia Beach", "Annapolis"] }
}
},
{
"$lookup": {
"from": "state",
"localField": "state",
"foreignField": "_id",
"as": "states"
}
},
{ "$unwind": "$states" },
{
"$group": {
"_id": null,
"relatedCities": {
"$push": {
"images": "$images",
"slug": "$slug",
"name": "$name",
"stateSlug": "$states.slug"
}
}
}
},
{
"$project": {
"_id": 0,
"name": { "$literal": "Lewes" },
"relatedCities": 1
}
}
],
newCity = db.city.aggregate(pipeline).toArray()[0];
db.city.save(newCity);