Як я можу (в MongoDB) об'єднати дані з кількох колекцій в одну колекцію?
Чи можу я використати зменшення карт і якщо так, то як?
Я б дуже вдячний за приклад, оскільки я є початківцем.
Як я можу (в MongoDB) об'єднати дані з кількох колекцій в одну колекцію?
Чи можу я використати зменшення карт і якщо так, то як?
Я б дуже вдячний за приклад, оскільки я є початківцем.
Відповіді:
Хоча ви не можете цього зробити в режимі реального часу, ви можете запустити зменшення карти в кілька разів, щоб об’єднати дані разом, використовуючи опцію "зменшити" на карті MongoDB 1.8+ / зменшити (див. 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"});
Цю техніку точно не слід виконувати з льоту. Він підходить для роботи з крон або чогось подібного, що періодично оновлює об'єднані дані. Ви, ймовірно, захочете запустити ensureIndexнову колекцію, щоб переконатися, що запити, які ви виконуєте проти неї, запускаються швидко (майте на увазі, що ваші дані все ще знаходяться в valueключі, тому якщо ви індексували comments_with_demographicsчас коментарів created, було бdb.comments_with_demographics.ensureIndex({"value.created": 1});
users_commentsколекції після першого блоку коду gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835
MongoDB 3.2 тепер дозволяє комбінувати дані з декількох колекцій в одну через етап агрегації $ пошуку . Як практичний приклад, скажімо, що у вас є дані про книги, розділені на дві різні колекції.
Перша колекція, що називається 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 із загальною кількістю проданих копій, вам доведеться трохи більше попрацювати, ймовірно, використовуючи посередницьку колекцію, яка буде, тоді, бути $ out до остаточної колекції.
$lookupчи не повинні всі "localField" і "ForeignField" дорівнювати "isbn"? не "_id" і "isbn"?
Якщо в mongodb немає об'ємної вставки, ми петлю всі об'єкти в small_collectionі вставляємо їх по одному в big_collection:
db.small_collection.find().forEach(function(obj){
db.big_collection.insert(obj)
});
Дуже базовий приклад з $ пошуку.
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"}
Тому що {$ unind: "$ userRoleData"} це поверне порожній або 0 результат, якщо не знайдено відповідного запису з $ пошуку.
Робити об'єднання в 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як null відповідати всій колекції.
{ $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" } }Voilà. Тепер у вас є набір результатів, що містить колекції, які ви хотіли об'єднати разом. Потім ви можете додати ще кілька етапів, щоб додатково його фільтрувати, сортувати, застосувати skip () та limit (). Практично все, що завгодно.
використовувати декілька $ пошуку для декількох колекцій у сукупності
запит:
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
}
}
У Монгоресторе є така особливість додавання до того, що вже є в базі даних, тому така поведінка може бути використана для поєднання двох колекцій:
Ще не спробував, але він може працювати швидше, ніж підхід до карти / зменшення.
Починаючи 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поєднує записи з даної колекції в документах, які вже є в конвеєрному конвеєрі. Після 2 етапів об'єднання, таким чином, у нас є всі записи користувачів, книг та фільмів.
Потім ми $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);
}
)
}
}
Ви можете передавати цій функції будь-яку кількість колекцій, перша буде цільовою. Усі решти колекцій є джерелами для передачі цільовій.
Фрагмент коду Ввічливість - кілька повідомлень про переповнення стека, включаючи цю.
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.