Как я могу (в MongoDB) объединить данные из нескольких коллекций в одну коллекцию?
Могу ли я использовать map-Reduce и если да, то как?
Я был бы очень признателен за пример, так как я новичок.
Как я могу (в MongoDB) объединить данные из нескольких коллекций в одну коллекцию?
Могу ли я использовать map-Reduce и если да, то как?
Я был бы очень признателен за пример, так как я новичок.
Ответы:
Несмотря на то, что вы не можете сделать это в режиме реального времени, вы можете запустить map-Reduction несколько раз, чтобы объединить данные, используя опцию «Reduce» Out в MongoDB 1.8+ map / проводить (см. Http://www.mongodb.org/ display / DOCS / MapReduce # MapReduce-Outputoptions ). У вас должен быть какой-то ключ в обеих коллекциях, который вы можете использовать как _id.
Например, допустим, у вас есть users
коллекция и comments
коллекция, и вы хотите иметь новую коллекцию, в которой есть демографические данные для каждого комментария.
Допустим, users
коллекция имеет следующие поля:
И тогда в comments
коллекции есть следующие поля:
Вы бы сделали эту карту / уменьшить:
var mapUsers, mapComments, reduce;
db.users_comments.remove();
// setup sample data - wouldn't actually use this in production
db.users.remove();
db.comments.remove();
db.users.save({firstName:"Rich",lastName:"S",gender:"M",country:"CA",age:"18"});
db.users.save({firstName:"Rob",lastName:"M",gender:"M",country:"US",age:"25"});
db.users.save({firstName:"Sarah",lastName:"T",gender:"F",country:"US",age:"13"});
var users = db.users.find();
db.comments.save({userId: users[0]._id, "comment": "Hey, what's up?", created: new ISODate()});
db.comments.save({userId: users[1]._id, "comment": "Not much", created: new ISODate()});
db.comments.save({userId: users[0]._id, "comment": "Cool", created: new ISODate()});
// end sample data setup
mapUsers = function() {
var values = {
country: this.country,
gender: this.gender,
age: this.age
};
emit(this._id, values);
};
mapComments = function() {
var values = {
commentId: this._id,
comment: this.comment,
created: this.created
};
emit(this.userId, values);
};
reduce = function(k, values) {
var result = {}, commentFields = {
"commentId": '',
"comment": '',
"created": ''
};
values.forEach(function(value) {
var field;
if ("comment" in value) {
if (!("comments" in result)) {
result.comments = [];
}
result.comments.push(value);
} else if ("comments" in value) {
if (!("comments" in result)) {
result.comments = [];
}
result.comments.push.apply(result.comments, value.comments);
}
for (field in value) {
if (value.hasOwnProperty(field) && !(field in commentFields)) {
result[field] = value[field];
}
}
});
return result;
};
db.users.mapReduce(mapUsers, reduce, {"out": {"reduce": "users_comments"}});
db.comments.mapReduce(mapComments, reduce, {"out": {"reduce": "users_comments"}});
db.users_comments.find().pretty(); // see the resulting collection
На этом этапе у вас будет новая коллекция под названием, users_comments
которая содержит объединенные данные, и теперь вы можете использовать ее. Все эти уменьшенные коллекции имеют _id
ключ, который вы выдавали в функциях карты, и тогда все значения являются подобъектом внутри value
ключа - значения не находятся на верхнем уровне этих сокращенных документов.
Это несколько простой пример. Вы можете повторить это с большим количеством коллекций, сколько хотите, чтобы создать сокращенную коллекцию. Вы также можете сделать резюме и агрегацию данных в процессе. Вероятно, вы бы определили более одной функции сокращения, поскольку логика для агрегирования и сохранения существующих полей становится более сложной.
Вы также заметите, что теперь существует один документ для каждого пользователя со всеми комментариями этого пользователя в массиве. Если бы мы объединяли данные, которые имеют отношение один-к-одному, а не один-ко-многим, это было бы плоско, и вы могли бы просто использовать функцию сокращения, например так:
reduce = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
Если вы хотите сгладить users_comments
коллекцию, чтобы она содержала один документ на комментарий, дополнительно запустите:
var map, reduce;
map = function() {
var debug = function(value) {
var field;
for (field in value) {
print(field + ": " + value[field]);
}
};
debug(this);
var that = this;
if ("comments" in this.value) {
this.value.comments.forEach(function(value) {
emit(value.commentId, {
userId: that._id,
country: that.value.country,
age: that.value.age,
comment: value.comment,
created: value.created,
});
});
}
};
reduce = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
db.users_comments.mapReduce(map, reduce, {"out": "comments_with_demographics"});
Эта техника определенно не должна выполняться на лету. Он подходит для работы cron или чего-то подобного, который периодически обновляет объединенные данные. Вы, вероятно, захотите запустить ensureIndex
новую коллекцию, чтобы убедиться, что запросы, которые вы выполняете против нее, выполняются быстро (имейте в виду, что ваши данные все еще находятся внутри value
ключа, поэтому, если вы захотите проиндексировать comments_with_demographics
время комментария created
, это будетdb.comments_with_demographics.ensureIndex({"value.created": 1});
users_comments
коллекции после первого блока кода gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835
MongoDB 3.2 теперь позволяет объединять данные из нескольких коллекций в одну через этап агрегации $ lookup . В качестве практического примера предположим, что у вас есть данные о книгах, разделенных на две разные коллекции.
Первый сбор называется books
, имея следующие данные:
{
"isbn": "978-3-16-148410-0",
"title": "Some cool book",
"author": "John Doe"
}
{
"isbn": "978-3-16-148999-9",
"title": "Another awesome book",
"author": "Jane Roe"
}
И называется вторая коллекция books_selling_data
, имеющая следующие данные:
{
"_id": ObjectId("56e31bcf76cdf52e541d9d26"),
"isbn": "978-3-16-148410-0",
"copies_sold": 12500
}
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 720050
}
{
"_id": ObjectId("56e31ce076cdf52e541d9d29"),
"isbn": "978-3-16-148999-9",
"copies_sold": 1000
}
Чтобы объединить обе коллекции, достаточно использовать $ lookup следующим образом:
db.books.aggregate([{
$lookup: {
from: "books_selling_data",
localField: "isbn",
foreignField: "isbn",
as: "copies_sold"
}
}])
После этой агрегации books
коллекция будет выглядеть следующим образом:
{
"isbn": "978-3-16-148410-0",
"title": "Some cool book",
"author": "John Doe",
"copies_sold": [
{
"_id": ObjectId("56e31bcf76cdf52e541d9d26"),
"isbn": "978-3-16-148410-0",
"copies_sold": 12500
}
]
}
{
"isbn": "978-3-16-148999-9",
"title": "Another awesome book",
"author": "Jane Roe",
"copies_sold": [
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 720050
},
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 1000
}
]
}
Важно отметить несколько вещей:
books_selling_data
не может быть очищена.Итак, в заключение, если вы хотите объединить обе коллекции, имея в данном случае плоское поле copy_sold с общим количеством проданных копий, вам придется работать немного больше, возможно, с использованием промежуточной коллекции, которая затем быть $ до окончательной коллекции.
$lookup
не все ли "localField" и "foreignField" равны "isbn"? не "_id", а "isbn"?
Если нет массовой вставки в mongodb, мы зациклим все объекты в small_collection
и вставим их один за другим в big_collection
:
db.small_collection.find().forEach(function(obj){
db.big_collection.insert(obj)
});
Очень простой пример с $ lookup.
db.getCollection('users').aggregate([
{
$lookup: {
from: "userinfo",
localField: "userId",
foreignField: "userId",
as: "userInfoData"
}
},
{
$lookup: {
from: "userrole",
localField: "userId",
foreignField: "userId",
as: "userRoleData"
}
},
{ $unwind: { path: "$userInfoData", preserveNullAndEmptyArrays: true }},
{ $unwind: { path: "$userRoleData", preserveNullAndEmptyArrays: true }}
])
Здесь используется
{ $unwind: { path: "$userInfoData", preserveNullAndEmptyArrays: true }},
{ $unwind: { path: "$userRoleData", preserveNullAndEmptyArrays: true }}
Вместо того
{ $unwind:"$userRoleData"}
{ $unwind:"$userRoleData"}
Потому что {$ unwind: "$ userRoleData"} возвращает пустой или 0 результат, если не найдена соответствующая запись с $ lookup.
Создание объединений в MongoDB в режиме «SQL UNION» возможно с использованием агрегации и поиска в одном запросе. Вот пример, который я протестировал, который работает с MongoDB 4.0:
// Create employees data for testing the union.
db.getCollection('employees').insert({ name: "John", type: "employee", department: "sales" });
db.getCollection('employees').insert({ name: "Martha", type: "employee", department: "accounting" });
db.getCollection('employees').insert({ name: "Amy", type: "employee", department: "warehouse" });
db.getCollection('employees').insert({ name: "Mike", type: "employee", department: "warehouse" });
// Create freelancers data for testing the union.
db.getCollection('freelancers').insert({ name: "Stephany", type: "freelancer", department: "accounting" });
db.getCollection('freelancers').insert({ name: "Martin", type: "freelancer", department: "sales" });
db.getCollection('freelancers').insert({ name: "Doug", type: "freelancer", department: "warehouse" });
db.getCollection('freelancers').insert({ name: "Brenda", type: "freelancer", department: "sales" });
// Here we do a union of the employees and freelancers using a single aggregation query.
db.getCollection('freelancers').aggregate( // 1. Use any collection containing at least one document.
[
{ $limit: 1 }, // 2. Keep only one document of the collection.
{ $project: { _id: '$$REMOVE' } }, // 3. Remove everything from the document.
// 4. Lookup collections to union together.
{ $lookup: { from: 'employees', pipeline: [{ $match: { department: 'sales' } }], as: 'employees' } },
{ $lookup: { from: 'freelancers', pipeline: [{ $match: { department: 'sales' } }], as: 'freelancers' } },
// 5. Union the collections together with a projection.
{ $project: { union: { $concatArrays: ["$employees", "$freelancers"] } } },
// 6. Unwind and replace root so you end up with a result set.
{ $unwind: '$union' },
{ $replaceRoot: { newRoot: '$union' } }
]);
Вот объяснение того, как это работает:
Создайте aggregate
из любой коллекции вашей базы данных, в которой есть хотя бы один документ. Если вы не можете гарантировать, что любая коллекция вашей базы данных не будет пустой, вы можете обойти эту проблему, создав в своей базе данных своего рода «фиктивную» коллекцию, содержащую один пустой документ, который будет там специально для выполнения запросов объединения.
Сделайте первый этап вашего конвейера, чтобы быть { $limit: 1 }
. Это лишит все документы коллекции кроме первого.
Удалите все поля оставшегося документа, используя $project
этап:
{ $project: { _id: '$$REMOVE' } }
Ваш агрегат теперь содержит один пустой документ. Пришло время добавить поиск для каждой коллекции, которую вы хотите объединить вместе. Вы можете использовать pipeline
поле , чтобы сделать некоторые конкретные фильтрации, или оставить localField
и foreignField
в нуле , чтобы соответствовать всей коллекции.
{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
{ $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
{ $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
Теперь у вас есть агрегат, содержащий один документ, который содержит 3 массива, например:
{
Collection1: [...],
Collection2: [...],
Collection3: [...]
}
Затем вы можете объединить их в один массив, используя $project
этап вместе с $concatArrays
оператором агрегирования:
{
"$project" :
{
"Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
}
}
Теперь у вас есть агрегат, содержащий один документ, в котором расположен массив, содержащий ваше объединение коллекций. Что еще предстоит сделать , это добавить $unwind
и на $replaceRoot
сцену , чтобы разделить ваш массив на отдельные документы:
{ $unwind: "$Union" },
{ $replaceRoot: { newRoot: "$Union" } }
Вуаля. Теперь у вас есть набор результатов, содержащий коллекции, которые вы хотите объединить вместе. Затем вы можете добавить дополнительные этапы для дальнейшей фильтрации, сортировки, применения skip () и limit (). Практически все, что вы хотите.
использовать несколько $ lookup для нескольких коллекций в агрегации
запрос:
db.getCollection('servicelocations').aggregate([
{
$match: {
serviceLocationId: {
$in: ["36728"]
}
}
},
{
$lookup: {
from: "orders",
localField: "serviceLocationId",
foreignField: "serviceLocationId",
as: "orders"
}
},
{
$lookup: {
from: "timewindowtypes",
localField: "timeWindow.timeWindowTypeId",
foreignField: "timeWindowTypeId",
as: "timeWindow"
}
},
{
$lookup: {
from: "servicetimetypes",
localField: "serviceTimeTypeId",
foreignField: "serviceTimeTypeId",
as: "serviceTime"
}
},
{
$unwind: "$orders"
},
{
$unwind: "$serviceTime"
},
{
$limit: 14
}
])
результат:
{
"_id" : ObjectId("59c3ac4bb7799c90ebb3279b"),
"serviceLocationId" : "36728",
"regionId" : 1.0,
"zoneId" : "DXBZONE1",
"description" : "AL HALLAB REST EMIRATES MALL",
"locationPriority" : 1.0,
"accountTypeId" : 1.0,
"locationType" : "SERVICELOCATION",
"location" : {
"makani" : "",
"lat" : 25.119035,
"lng" : 55.198694
},
"deliveryDays" : "MTWRFSU",
"timeWindow" : [
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32cde"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "06:00",
"closeTime" : "08:00"
},
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32cdf"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "09:00",
"closeTime" : "10:00"
},
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32ce0"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "10:30",
"closeTime" : "11:30"
},
"accountId" : 1.0
}
],
"address1" : "",
"address2" : "",
"phone" : "",
"city" : "",
"county" : "",
"state" : "",
"country" : "",
"zipcode" : "",
"imageUrl" : "",
"contact" : {
"name" : "",
"email" : ""
},
"status" : "ACTIVE",
"createdBy" : "",
"updatedBy" : "",
"updateDate" : "",
"accountId" : 1.0,
"serviceTimeTypeId" : "1",
"orders" : [
{
"_id" : ObjectId("59c3b291f251c77f15790f92"),
"orderId" : "AQ18O1704264",
"serviceLocationId" : "36728",
"orderNo" : "AQ18O1704264",
"orderDate" : "18-Sep-17",
"description" : "AQ18O1704264",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 296.0,
"size2" : 3573.355,
"size3" : 240.811,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "BNWB020",
"size1" : 15.0,
"size2" : 78.6,
"size3" : 6.0
},
{
"ItemId" : "BNWB021",
"size1" : 20.0,
"size2" : 252.0,
"size3" : 11.538
},
{
"ItemId" : "BNWB023",
"size1" : 15.0,
"size2" : 285.0,
"size3" : 16.071
},
{
"ItemId" : "CPMW112",
"size1" : 3.0,
"size2" : 25.38,
"size3" : 1.731
},
{
"ItemId" : "MMGW001",
"size1" : 25.0,
"size2" : 464.375,
"size3" : 46.875
},
{
"ItemId" : "MMNB218",
"size1" : 50.0,
"size2" : 920.0,
"size3" : 60.0
},
{
"ItemId" : "MMNB219",
"size1" : 50.0,
"size2" : 630.0,
"size3" : 40.0
},
{
"ItemId" : "MMNB220",
"size1" : 50.0,
"size2" : 416.0,
"size3" : 28.846
},
{
"ItemId" : "MMNB270",
"size1" : 50.0,
"size2" : 262.0,
"size3" : 20.0
},
{
"ItemId" : "MMNB302",
"size1" : 15.0,
"size2" : 195.0,
"size3" : 6.0
},
{
"ItemId" : "MMNB373",
"size1" : 3.0,
"size2" : 45.0,
"size3" : 3.75
}
],
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b291f251c77f15790f9d"),
"orderId" : "AQ137O1701240",
"serviceLocationId" : "36728",
"orderNo" : "AQ137O1701240",
"orderDate" : "18-Sep-17",
"description" : "AQ137O1701240",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 28.0,
"size2" : 520.11,
"size3" : 52.5,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "MMGW001",
"size1" : 25.0,
"size2" : 464.38,
"size3" : 46.875
},
{
"ItemId" : "MMGW001-F1",
"size1" : 3.0,
"size2" : 55.73,
"size3" : 5.625
}
],
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b291f251c77f15790fd8"),
"orderId" : "AQ110O1705036",
"serviceLocationId" : "36728",
"orderNo" : "AQ110O1705036",
"orderDate" : "18-Sep-17",
"description" : "AQ110O1705036",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 60.0,
"size2" : 1046.0,
"size3" : 68.0,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "MMNB218",
"size1" : 50.0,
"size2" : 920.0,
"size3" : 60.0
},
{
"ItemId" : "MMNB219",
"size1" : 10.0,
"size2" : 126.0,
"size3" : 8.0
}
],
"accountId" : 1.0
}
],
"serviceTime" : {
"_id" : ObjectId("59c3b07cb7799c90ebb32cdc"),
"serviceTimeTypeId" : "1",
"serviceTimeType" : "nohelper",
"description" : "",
"fixedTime" : 30.0,
"variableTime" : 0.0,
"accountId" : 1.0
}
}
Mongorestore имеет эту функцию добавления поверх того, что уже есть в базе данных, поэтому это поведение можно использовать для объединения двух коллекций:
Пока не пробовал, но он может работать быстрее, чем подход "карта / уменьшение".
Начнем с того Mongo 4.4
, что мы можем достичь этого объединения в конвейере агрегации, связав новый $unionWith
этап агрегации с $group
новым $accumulator
оператором:
// > db.users.find()
// [{ user: 1, name: "x" }, { user: 2, name: "y" }]
// > db.books.find()
// [{ user: 1, book: "a" }, { user: 1, book: "b" }, { user: 2, book: "c" }]
// > db.movies.find()
// [{ user: 1, movie: "g" }, { user: 2, movie: "h" }, { user: 2, movie: "i" }]
db.users.aggregate([
{ $unionWith: "books" },
{ $unionWith: "movies" },
{ $group: {
_id: "$user",
user: {
$accumulator: {
accumulateArgs: ["$name", "$book", "$movie"],
init: function() { return { books: [], movies: [] } },
accumulate: function(user, name, book, movie) {
if (name) user.name = name;
if (book) user.books.push(book);
if (movie) user.movies.push(movie);
return user;
},
merge: function(userV1, userV2) {
if (userV2.name) userV1.name = userV2.name;
userV1.books.concat(userV2.books);
userV1.movies.concat(userV2.movies);
return userV1;
},
lang: "js"
}
}
}}
])
// { _id: 1, user: { books: ["a", "b"], movies: ["g"], name: "x" } }
// { _id: 2, user: { books: ["c"], movies: ["h", "i"], name: "y" } }
$unionWith
объединяет записи из данной коллекции в документы, уже находящиеся в конвейере агрегации. После двух этапов объединения у нас есть все пользователи, книги и записи фильмов в конвейере.
Затем мы $group
регистрируем $user
и накапливаем элементы, используя $accumulator
оператор, позволяющий настраивать накопления документов по мере их группировки:
accumulateArgs
.init
определяет состояние, которое будет накапливаться при группировании элементов.accumulate
функция позволяет выполнять пользовательские действия с записью группируется, чтобы построить накопленное состояние. Например, если для сгруппированного элемента book
определено поле, мы обновляем books
часть состояния.merge
используется для объединения двух внутренних состояний. Он используется только для агрегатов, работающих на сегментированных кластерах или когда операция превышает пределы памяти.Да, вы можете: Возьмите эту служебную функцию, которую я написал сегодня:
function shangMergeCol() {
tcol= db.getCollection(arguments[0]);
for (var i=1; i<arguments.length; i++){
scol= db.getCollection(arguments[i]);
scol.find().forEach(
function (d) {
tcol.insert(d);
}
)
}
}
Вы можете передать в эту функцию любое количество коллекций, первая из которых будет целевой. Все остальные коллекции являются источниками, которые необходимо перенести в целевой.
Фрагмент кода. Courtesy-Несколько сообщений о переполнении стека, включая этот.
db.cust.drop();
db.zip.drop();
db.cust.insert({cust_id:1, zip_id: 101});
db.cust.insert({cust_id:2, zip_id: 101});
db.cust.insert({cust_id:3, zip_id: 101});
db.cust.insert({cust_id:4, zip_id: 102});
db.cust.insert({cust_id:5, zip_id: 102});
db.zip.insert({zip_id:101, zip_cd:'AAA'});
db.zip.insert({zip_id:102, zip_cd:'BBB'});
db.zip.insert({zip_id:103, zip_cd:'CCC'});
mapCust = function() {
var values = {
cust_id: this.cust_id
};
emit(this.zip_id, values);
};
mapZip = function() {
var values = {
zip_cd: this.zip_cd
};
emit(this.zip_id, values);
};
reduceCustZip = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
if ("cust_id" in value) {
if (!("cust_ids" in result)) {
result.cust_ids = [];
}
result.cust_ids.push(value);
} else {
for (field in value) {
if (value.hasOwnProperty(field) ) {
result[field] = value[field];
}
};
}
});
return result;
};
db.cust_zip.drop();
db.cust.mapReduce(mapCust, reduceCustZip, {"out": {"reduce": "cust_zip"}});
db.zip.mapReduce(mapZip, reduceCustZip, {"out": {"reduce": "cust_zip"}});
db.cust_zip.find();
mapCZ = function() {
var that = this;
if ("cust_ids" in this.value) {
this.value.cust_ids.forEach(function(value) {
emit(value.cust_id, {
zip_id: that._id,
zip_cd: that.value.zip_cd
});
});
}
};
reduceCZ = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
db.cust_zip_joined.drop();
db.cust_zip.mapReduce(mapCZ, reduceCZ, {"out": "cust_zip_joined"});
db.cust_zip_joined.find().pretty();
var flattenMRCollection=function(dbName,collectionName) {
var collection=db.getSiblingDB(dbName)[collectionName];
var i=0;
var bulk=collection.initializeUnorderedBulkOp();
collection.find({ value: { $exists: true } }).addOption(16).forEach(function(result) {
print((++i));
//collection.update({_id: result._id},result.value);
bulk.find({_id: result._id}).replaceOne(result.value);
if(i%1000==0)
{
print("Executing bulk...");
bulk.execute();
bulk=collection.initializeUnorderedBulkOp();
}
});
bulk.execute();
};
flattenMRCollection("mydb","cust_zip_joined");
db.cust_zip_joined.find().pretty();
Вы должны сделать это на уровне приложения. Если вы используете ORM, он может использовать аннотации (или что-то подобное) для извлечения ссылок, которые существуют в других коллекциях. Я работал только с Morphia , и @Reference
аннотация извлекает ссылочную сущность при запросе, поэтому я могу избежать делать это самостоятельно в коде.
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});
, достаточно. Пожалуйста, укажите используемый драйвер (java, php, ...), если вы не используете оболочку mongo.