Вот еще одно итерационное решение для современных браузеров:
Object.keys(obj).filter(function(k, i) {
return i >= 100 && i < 300;
}).forEach(function(k) {
console.log(obj[k]);
});
Или еще короче:
Object.keys(obj).forEach(function(k, i) {
if (i >= 100 && i < 300) {
console.log(obj[k]);
}
});
Однако вы должны учитывать, что свойства объекта JavaScript не сортируются, т. е. не имеют порядка.
Что касается Монго 3.2, ответы на этот вопрос больше не верны. Новый оператор $ lookup, добавленный в конвейер агрегации, по существу идентичен левому внешнему соединению:
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>
}
}
Конечно, Mongo является не реляционной базой данных, а разработчики стараются рекомендовать конкретные варианты использования для $ lookup, но по крайней мере, начиная с 3.2, соединение теперь возможно с MongoDB.
Вы можете присоединиться к двум коллекциям в Монго, используя поиск, который предлагается в версии 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.
До 3.2.6 Mongodb не поддерживает запрос соединения как mysql. ниже решения, которое работает для вас.
db.getCollection('comments').aggregate([
{$match : {pid : 444}},
{$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
])
При правильной комбинации $ lookup, $ project и $ match вы можете присоединиться к нескольким таблицам по нескольким параметрам. Это связано с тем, что они могут быть связаны несколько раз.
Предположим, что мы хотим сделать следующее ( reference )
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: Свяжите все таблицы
, вы можете $ lookup сколько угодно таблиц.
$ lookup - по одному для каждой таблицы в запросе
$ unwind - поскольку данные денормализированы правильно, иначе они завернуты в массивы
Python code ..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "R"}
])
Шаг 2: Определите все условные выражения
$ project: определите здесь все условные операторы и все переменные, которые вы хотите выбрать.
Python Code ..
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: Присоедините все условные обозначения
$ match - присоедините все условия, используя OR или AND и т. д. Их могут быть кратные ,
$ project: undefine all conditionals
Python Code ..
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
}}
])
Практически любая комбинация таблиц, условных обозначений и объединений может быть выполнена таким образом ,
playORM может сделать это для вас, используя S-SQL (масштабируемый SQL), который просто добавляет разделение, так что вы можете делать объединения внутри разделов.
Выполняет левое внешнее соединение в незащищенном наборе в той же базе данных для фильтрации в документах из «объединенной» коллекции для обработки. Для каждого входного документа этап $ lookup добавляет новое поле массива, элементы которого являются соответствующими документами из «объединенной» коллекции. Эта стадия $ lookup передает эти измененные документы на следующий этап. Этап $ lookup имеет следующие синтаксисы:
Чтобы выполнить совпадение равенства между полем из входных документов с полем из документов «объединенной» коллекции, этап $ 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>
}
}
Операция будет соответствовать следующему выражению псевдо-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> );
Вот пример коллекции "join" * Актеры и фильмы:
https://github.com/mongodb/cookbook/blob/master/ content / patterns / pivot.txt
Использует метод .mapReduce()
* join - альтернативу объединению в документарно-ориентированных базах данных
Мы можем объединить две коллекции, используя sub-запрос mongoDB. Вот пример, Комментарии -
`db.commentss.insert([
{ uid:12345, pid:444, comment:"blah" },
{ uid:12345, pid:888, comment:"asdf" },
{ uid:99999, pid:444, comment:"qwer" }])`
Пользователи -
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);
}
);`
Получить результат из недавно созданная коллекция -
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"
}
]
}`
Надеюсь, что это поможет.
Эта страница на официальном сайте mongodb адресует точно этот вопрос:
http://docs.mongodb.org/ecosystem/tutorial/model-data- for-ruby-on-rails /
Когда мы показываем наш список историй, нам нужно будет показать имя пользователя, разместившего историю. Если бы мы использовали реляционную базу данных, мы могли бы выполнить соединение с пользователями и магазинами и получить все наши объекты в одном запросе. Но MongoDB не поддерживает объединения, и поэтому время от времени требуется бит денормализации. Здесь это означает кеширование атрибута «имя пользователя».
Реляционные пуристы уже чувствуют себя неловко, как будто мы нарушаем какой-то универсальный закон. Но давайте иметь в виду, что коллекции MongoDB не эквивалентны реляционным таблицам; каждая из которых служит уникальной проектной цели. Нормализованная таблица обеспечивает атомный изолированный кусок данных. Однако документ более тесно представляет собой объект в целом. В случае сайта социальных новостей можно утверждать, что имя пользователя является неотъемлемой частью истории, опубликованной.
blockquote>
Вы можете сделать это, используя конвейер агрегации, но это боль, чтобы написать его самостоятельно.
Вы можете использовать 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
для решения этой точной проблемы.
Но у меня есть решение о разрешении для MOngo на Git Кстати , вставляет код - у него есть имя фильма, но идентификатор фильма noi.
У вас есть коллекция Актеров с массивом фильмов, которые они сделали.
Вы хотите создать коллекцию фильмов с массивом Актеров в каждом.
Некоторые данные образца
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'] });
Нам нужно прокрутить каждый фильм в документе Actor и выдать каждый фильм по отдельности.
Улов здесь находится в фазе уменьшения. Мы не можем испускать массив из фазы уменьшения, поэтому мы должны построить массив Actors внутри возвращаемого документа «value».
Код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, который содержит массив. Также обратите внимание, что карта испускает ту же структуру.
Запустите следующую команду, чтобы выполнить карту / уменьшить, вывести ее в коллекцию «pivot» и напечатать результат:
printjson (db. actors.mapReduce (карта, уменьшить, «поворот»)); db.pivot.find (). forEach (printjson);
Вот пример вывода, обратите внимание, что у «Pretty Woman» и «Runaway Bride» есть как «Richard Gere», так и «Julia Roberts».
{ "_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" ] } }
Вы можете запускать SQL-запросы, включая объединение на MongoDB с mongo_fdw из Postgres.
Нет, похоже, что вы делаете это неправильно. Соединения MongoDB являются «клиентской стороной». Очень похоже на то, что вы сказали:
На данный момент я получаю комментарии, соответствующие моим критериям, затем выясняя все uid в этом наборе результатов, получая пользовательские объекты и объединяя их с комментариями. Похоже, я делаю это неправильно.
blockquote>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 все еще есть.
MongoDB не разрешает объединения, но вы можете использовать плагины для его обработки. Проверьте плагин mongo-join. Это лучшее, и я уже использовал его. Вы можете установить его с помощью 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;
});
});
Существует спецификация, которую поддерживает множество драйверов, называемая DBRef.
DBRef - это более формальная спецификация для создания ссылок между документами. DBRefs (обычно) включают имя коллекции, а также идентификатор объекта. Большинство разработчиков используют только DBRefs, если коллекция может измениться с одного документа на другой. Если ваша ссылочная коллекция всегда будет одинаковой, рекомендации по руководству, описанные выше, более эффективны.
blockquote>Взято из MongoDB Документация: Модели данных> Ссылка на модель данных> Ссылки на базы данных
Мы можем объединить / объединить все данные внутри одной коллекции с простой функцией в нескольких строках с помощью клиентской консоли 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" : [ ]
}
Надеюсь, эти строки помогут вам.
Вы должны сделать это так, как вы описали. MongoDB является нереляционной базой данных и не поддерживает объединения.
Это зависит от того, что вы пытаетесь сделать.
В настоящее время вы настроили его как нормализованную базу данных, и это нормально, и то, как вы это делаете, уместно.
Однако есть и другие способы сделать это.
У вас может быть коллекция сообщений, в которой есть встроенные комментарии для каждого сообщения со ссылками на пользователей, которые вы можете итеративно запросить. Вы можете сохранить имя пользователя с комментариями, вы можете сохранить их все в одном документе.
Вещь с NoSQL предназначена для гибких схем и очень быстрого чтения и записи. В типичной ферме больших данных база данных является самым узким местом, у вас меньше двигателей баз данных, чем у приложений и передних серверов ... они дороже, но более мощные, а также на жестком диске сравнительно дешево. Нормализация исходит из концепции попытки сэкономить место, но она требует затрат на то, чтобы ваши базы данных выполняли сложные соединения и проверяли целостность отношений, выполняя каскадные операции.
С NoSQL, если вы согласитесь, что избыточность и пространство для хранения не являются проблемами из-за их стоимости (как в процессорное время, необходимое для обновления и затраты на жесткий диск для хранения дополнительных данных), денормализация не является проблемой (для встроенных массивов, которые становятся сотнями тысяч элементов, это может быть проблемой производительности, но большую часть времени это не проблема). Кроме того, у вас будет несколько серверов приложений и интерфейсов для каждого кластера баз данных. Попросите их сделать тяжелый подъем соединений и позволить серверам баз данных придерживаться чтения и записи.
TL; DR: То, что вы делаете, прекрасно, и есть другие способы сделать это. Ознакомьтесь с образцами моделей данных документации mongodb для некоторых замечательных примеров. http://docs.mongodb.org/manual/data-modeling/
Как уже указывалось, вы пытаетесь создать реляционную базу данных из какой-либо реляционной базы данных, которую вы действительно не хотите делать, но в любом случае, если у вас есть случай, когда вы должны это сделать, это решение, которое вы можете использовать , Сначала мы делаем поиск foreach в коллекции A (или в вашем случае пользователей), и затем мы получаем каждый элемент как объект, тогда мы используем свойство объекта (в вашем случае 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
}
});