如何执行的SQL MongoDB中加入相同呢?
例如说,你有两个集合(用户和评论),我想拉所有的评论具有PID = 444为每个用户信息一起。
comments
{ uid:12345, pid:444, comment="blah" }
{ uid:12345, pid:888, comment="asdf" }
{ uid:99999, pid:444, comment="qwer" }
users
{ uid:12345, name:"john" }
{ uid:99999, name:"mia" }
有没有一种方法来把所有与某一领域的意见(如...找到({PID:444})),并一气呵成每个评论相关联的用户信息?
目前,我首先得到符合我的标准,它的意见,然后找出所有的UID在该结果集,得到了用户对象,并与评论的结果将它们合并。 好像我做错了。
Answer 1:
作为蒙戈3.2的这个问题的答案大多是不再正确。 新的$查找运营商加入到聚合管道是基本相同的左外连接:
https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup
从文档:
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
当然蒙戈不是一个关系数据库和开发者正在仔细地推荐$查找的特定使用案例,但至少为3.2做的加入,现在可以用MongoDB的。
Answer 2:
在MongoDB的官方网站本页面地址正是这个问题:
http://docs.mongodb.org/ecosystem/tutorial/model-data-for-ruby-on-rails/
当我们展示我们的故事的列表,我们需要证明谁张贴的故事的用户名。 如果我们使用关系数据库中,我们可以执行用户和存储加盟,让我们在一个查询中的所有对象。 但是MongoDB中不支持联接等,有时需要非规范化的位。 在这里,这意味着缓存的“用户名”属性。
关系纯粹主义者可能已经感到不安,因为如果我们违反了一些普遍规律。 但是,让我们记住,MongoDB的集合不等同于关系表; 每个供应独特的设计目标。 归一化的表格提供数据的一个原子,隔离块。 文档,但是,更加紧密地代表了一个对象作为一个整体。 社交新闻网站的情况下,可以说,在被张贴的故事,一个用户名是内在的。
Answer 3:
我们可以合并/加入的所有数据只有一个集合内,在使用MongoDB的客户端控制台几行简单的功能,现在我们可能能够执行所需的查询。 下面一个完整的例子,
.-作者:
db.authors.insert([
{
_id: 'a1',
name: { first: 'orlando', last: 'becerra' },
age: 27
},
{
_id: 'a2',
name: { first: 'mayra', last: 'sanchez' },
age: 21
}
]);
.-分类:
db.categories.insert([
{
_id: 'c1',
name: 'sci-fi'
},
{
_id: 'c2',
name: 'romance'
}
]);
.-书籍
db.books.insert([
{
_id: 'b1',
name: 'Groovy Book',
category: 'c1',
authors: ['a1']
},
{
_id: 'b2',
name: 'Java Book',
category: 'c2',
authors: ['a1','a2']
},
]);
.-图书借阅
db.lendings.insert([
{
_id: 'l1',
book: 'b1',
date: new Date('01/01/11'),
lendingBy: 'jose'
},
{
_id: 'l2',
book: 'b1',
date: new Date('02/02/12'),
lendingBy: 'maria'
}
]);
。- 魔术:
db.books.find().forEach(
function (newBook) {
newBook.category = db.categories.findOne( { "_id": newBook.category } );
newBook.lendings = db.lendings.find( { "book": newBook._id } ).toArray();
newBook.authors = db.authors.find( { "_id": { $in: newBook.authors } } ).toArray();
db.booksReloaded.insert(newBook);
}
);
.-获取新的收集数据:
db.booksReloaded.find().pretty()
.-响应:)
{
"_id" : "b1",
"name" : "Groovy Book",
"category" : {
"_id" : "c1",
"name" : "sci-fi"
},
"authors" : [
{
"_id" : "a1",
"name" : {
"first" : "orlando",
"last" : "becerra"
},
"age" : 27
}
],
"lendings" : [
{
"_id" : "l1",
"book" : "b1",
"date" : ISODate("2011-01-01T00:00:00Z"),
"lendingBy" : "jose"
},
{
"_id" : "l2",
"book" : "b1",
"date" : ISODate("2012-02-02T00:00:00Z"),
"lendingBy" : "maria"
}
]
}
{
"_id" : "b2",
"name" : "Java Book",
"category" : {
"_id" : "c2",
"name" : "romance"
},
"authors" : [
{
"_id" : "a1",
"name" : {
"first" : "orlando",
"last" : "becerra"
},
"age" : 27
},
{
"_id" : "a2",
"name" : {
"first" : "mayra",
"last" : "sanchez"
},
"age" : 21
}
],
"lendings" : [ ]
}
我希望这行可以帮助你。
Answer 4:
你必须做你所描述的方式。 MongoDB是一个非关系型数据库,不支持加入。
Answer 5:
这里的“加入” * 演员和电影收藏品的例子:
https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt
它利用的.mapReduce()
方法
*加入 -可替代参加面向文档的数据库
Answer 6:
正如其他人所指出的,你正试图创建无关系数据库中的关系型数据库,你真的不想做,但不管怎么说,如果你有,你必须做到这一点这里是你可以用一个解决方案的情况下。 我们首先做集合的一个foreach找到(或在您的情况下,用户),然后我们得到每一个对象,然后我们使用对象属性(在你的情况下,UID)项目我们的第二个集合中查找,如果我们(在你的情况评论)可以找到它,然后我们有一个比赛,我们可以打印或用它做什么。 希望这可以帮助你,祝你好运:)
db.users.find().forEach(
function (object) {
var commonInBoth=db.comments.findOne({ "uid": object.uid} );
if (commonInBoth != null) {
printjson(commonInBoth) ;
printjson(object) ;
}else {
// did not match so we don't care in this case
}
});
Answer 7:
随着$查询 ,$项目和$匹配的正确组合,您可以加入多个参数多发表。 这是因为他们可以链接多次。
假设我们想要做以下( 参考 )
SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND
S.MOB IS NOT NULL
第1步:连接所有表
只要你想,你可以查找$尽可能多的表。
$查找 -一个用于查询每个表
$放松 -因为数据被正确地去归一化,否则包裹在阵列
Python代码..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "R"}
])
第2步:定义所有条件语句
$项目 :这里定义的所有条件语句,加上所有的变量,你想选择。
Python代码..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "R"},
# define conditionals + variables
{"$project": {
"midEq": {"$eq": ["$MID", "$R.MID"]},
"ID": 1, "MOB": 1, "MID": 1
}}
])
第3步:加入所有的条件
$比赛 -使用OR或加入的所有条件等有可能是这些倍数。
$项目 :取消定义的所有条件语句
Python代码..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "$R"},
# define conditionals + variables
{"$project": {
"midEq": {"$eq": ["$MID", "$R.MID"]},
"ID": 1, "MOB": 1, "MID": 1
}},
# join all conditionals
{"$match": {
"$and": [
{"R.TIM": {"$gt": 0}},
{"MOB": {"$exists": True}},
{"midEq": {"$eq": True}}
]}},
# undefine conditionals
{"$project": {
"midEq": 0
}}
])
相当多的表,条件任意组合,并加入可以通过这种方式来完成。
Answer 8:
这取决于你想要做什么。
您目前有它设置为一个规范化的数据库,这是很好的,和你正在做的方式是适当的。
不过,也有这样做的其他方式。
你可以有一个职位的集合,嵌入了评论每篇文章一起,你可以反复查询,以获得用户的引用。 你可以存储用户名与评论,你可以将它们全部存储一个文件内。
与NoSQL的问题是它的设计灵活的架构和非常快的读写。 在一个典型的大数据场的数据库是最大的瓶颈,你有较少的数据库引擎比你的应用程序和前端服务器...他们更昂贵,但功能更强大,也硬盘空间是非常便宜的比较。 标准化来自试图以节省空间的概念,但它在制作是有代价的数据库进行复杂的联接和验证关系的完整性,执行级联操作。 所有这一切都节省了,如果有些头疼,他们设计合理的数据库开发人员。
随着NoSQL的,如果你接受的冗余和存储空间都没有,因为他们的成本问题(无论是在做更新和存储额外的数据的硬盘驱动器的成本所需的处理器时间),反规范化是不是一个问题(嵌入式阵列即成为几十万的项目也可以是一个性能问题,但多数认为这不是一个问题)的时间。 此外,您将有多个应用和前端服务器对每个数据库集群。 让他们做繁重的加入,让数据库服务器坚持阅读和写作。
TL; DR:你在做什么是好的,也有这样做的其他方式。 退房的MongoDB文档的数据模型模式的一些很好的例子。 http://docs.mongodb.org/manual/data-modeling/
Answer 9:
您可以使用它在3.2版本中提供查找连接两个集合中蒙戈。 在你的情况下,查询将
db.comments.aggregate({
$lookup:{
from:"users",
localField:"uid",
foreignField:"uid",
as:"users_comments"
}
})
或者你也可以相对于加入到用户,那么就会出现下面给出一个变化不大。
db.users.aggregate({
$lookup:{
from:"comments",
localField:"uid",
foreignField:"uid",
as:"users_comments"
}
})
它的工作只是同左和右SQL加盟。
Answer 10:
还有的是,不少司机都支持这就是所谓DBREF的规范。
DBREF是用于创建文档之间的引用一个更正式的规范。 DBREFS(一般),包括集合名称,以及对象ID。 大多数开发人员只使用如果DBREFS收集可以改变从一个文档到下一个。 如果您引用集合将始终是相同的,上面列出的参考手册更有效。
从MongoDB的资料为准: 数据模型>数据模型参考> 数据库引用
Answer 11:
$查询(聚集)
执行左外连接到unsharded集合在同一个数据库中的“加盟”收集处理文档进行过滤。 要输入的文件中,$查找阶段增加的元素是从“加盟”集合匹配的文档的新阵列领域。 在$查找工作台会将这些文件重塑到下一阶段。 在$查找阶段具有以下语法:
平等匹配
从与从“加盟”收集的文件字段输入文档执行现场之间的平等的比赛,该$查找阶段的语法如下:
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
操作将对应于以下伪SQL语句:
SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
FROM <collection to join>
WHERE <pipeline> );
蒙戈网址
Answer 12:
3.2.6之前的MongoDB不支持联接查询作为像MySQL。 下面的解决方案,为你的作品。
db.getCollection('comments').aggregate([
{$match : {pid : 444}},
{$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
])
Answer 13:
您可以运行SQL查询,包括参加有关MongoDB与mongo_fdw从Postgres的。
Answer 14:
MongoDB中不允许加入,但你可以使用插件来处理。 检查蒙戈 - 加入插件。 这是最好的,我已经使用过了。 您可以直接使用NPM这样安装npm install mongo-join
。 您可以检查出有例子完整的文档 。
(++)真正有用的工具,当我们需要加入(N)的集合
( - ),我们可以申请条件只是在查询的顶级
例
var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
Database.collection('Appoint', function (err, Appoints) {
/* we can put conditions just on the top level */
Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
full_date :{ $lte: end_date }}, function (err, cursor) {
var join = new Join(Database).on({
field: '_id_Doctor', // <- field in Appoints document
to: '_id', // <- field in User doc. treated as ObjectID automatically.
from: 'User' // <- collection name for User doc
}).on({
field: '_id_Patient', // <- field in Appoints doc
to: '_id', // <- field in User doc. treated as ObjectID automatically.
from: 'User' // <- collection name for User doc
})
join.toArray(cursor, function (err, joinedDocs) {
/* do what ever you want here */
/* you can fetch the table and apply your own conditions */
.....
.....
.....
resp.status(200);
resp.json({
"status": 200,
"message": "success",
"Appoints_Range": joinedDocs,
});
return resp;
});
});
Answer 15:
您可以使用聚合管道做到这一点,但它是自己编写一个痛。
您可以使用mongo-join-query
,从查询自动创建聚合管道。
这是您的查询会是什么样子:
const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");
joinQuery(
mongoose.models.Comment,
{
find: { pid:444 },
populate: ["uid"]
},
(err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);
您的结果将在用户对象uid
字段,可以链接深,只要你想尽可能多的水平。 您可以填充参考用户,这使得参照组,这使得引用到别的东西,等等。
免责声明 :我写了mongo-join-query
来解决这个确切的问题。
Answer 16:
playORM可以使用它只是增加了划分,这样你可以做分区中加入S-SQL(可扩展SQL)为你做它。
Answer 17:
不,它似乎并不像你这样做是错误的。 MongoDB的连接是“客户端”。 很像你说:
目前,我首先得到符合我的标准,它的意见,然后找出所有的UID在该结果集,得到了用户对象,并与评论的结果将它们合并。 好像我做错了。
1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.
这不是一个“真正”的加入,但它实际上是很多比SQL联接,因为你没有处理的重复的行更多有用的“多”双面连接,而不是你的装修最初选择集。
有废话和FUD此页面上的很多。 原来,5年以后的MongoDB仍然是一个事。
Answer 18:
我想,如果你需要标准化的数据表 - 你需要尝试一些其他的数据库解决方案。
但我已经是sollution为蒙戈上foun 的Git顺便说一句,在插入的代码-它拥有电影的名字, 但NOI电影的ID。
问题
你有演员的集合与他们已经做了电影的数组。
要生成电影的集合在每个演员的数组。
一些示例数据
db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });
解
我们需要遍历每部电影的演员文档中并单独发出每部电影。
这里的前提条件是在减少的阶段。 我们不能发出从减少相位的排列,所以我们必须建立返回的“价值”的文档中的演员阵列。
The code
map = function() {
for(var i in this.movies){
key = { movie: this.movies[i] };
value = { actors: [ this.actor ] };
emit(key, value);
}
}
reduce = function(key, values) {
actor_list = { actors: [] };
for(var i in values) {
actor_list.actors = values[i].actors.concat(actor_list.actors);
}
return actor_list;
}
注意actor_list实际上是如何包含数组JavaScript对象。 还要注意,地图发出相同的结构。
运行以下命令以执行的map / reduce,它输出的“支点”的收集和打印结果:
printjson(db.actors.mapReduce(地图,减少, “枢轴”)); db.pivot.find()的forEach(printjson)。
下面是示例输出,请注意,“漂亮女人”和“逃跑新娘”兼得“李察·基尔”和“朱莉娅·罗伯茨”。
{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
Answer 19:
我们可以通过使用MongoDB的子查询合并两个集合。 下面是例子,Commentss--
`db.commentss.insert([
{ uid:12345, pid:444, comment:"blah" },
{ uid:12345, pid:888, comment:"asdf" },
{ uid:99999, pid:444, comment:"qwer" }])`
Userss--
db.userss.insert([
{ uid:12345, name:"john" },
{ uid:99999, name:"mia" }])
MongoDB的子查询JOIN--
`db.commentss.find().forEach(
function (newComments) {
newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
db.newCommentUsers.insert(newComments);
}
);`
从获得新生成的Collection--导致
db.newCommentUsers.find().pretty()
结果 -
`{
"_id" : ObjectId("5511236e29709afa03f226ef"),
"uid" : 12345,
"pid" : 444,
"comment" : "blah",
"userss" : [
{
"_id" : ObjectId("5511238129709afa03f226f2"),
"uid" : 12345,
"name" : "john"
}
]
}
{
"_id" : ObjectId("5511236e29709afa03f226f0"),
"uid" : 12345,
"pid" : 888,
"comment" : "asdf",
"userss" : [
{
"_id" : ObjectId("5511238129709afa03f226f2"),
"uid" : 12345,
"name" : "john"
}
]
}
{
"_id" : ObjectId("5511236e29709afa03f226f1"),
"uid" : 99999,
"pid" : 444,
"comment" : "qwer",
"userss" : [
{
"_id" : ObjectId("5511238129709afa03f226f3"),
"uid" : 99999,
"name" : "mia"
}
]
}`
希望如此,这将帮助。
文章来源: How do I perform the SQL Join equivalent in MongoDB?