(MongoDB'de) birden çok koleksiyondaki verileri tek bir koleksiyonda nasıl birleştirebilirim?
Harita küçültmeyi kullanabilir miyim, öyleyse nasıl?
Bir acemi olduğum için bazı örnekleri çok takdir ediyorum.
(MongoDB'de) birden çok koleksiyondaki verileri tek bir koleksiyonda nasıl birleştirebilirim?
Harita küçültmeyi kullanabilir miyim, öyleyse nasıl?
Bir acemi olduğum için bazı örnekleri çok takdir ediyorum.
Yanıtlar:
Bunu gerçek zamanlı olarak yapamasanız da, MongoDB 1.8+ harita / azaltmadaki "azaltma" seçeneğini kullanarak verileri birleştirmek için harita küçültmeyi birden çok kez çalıştırabilirsiniz (bkz. Http://www.mongodb.org/ display / DOCS / MapReduce # MapReduce-Outputoptions ). Her iki koleksiyonda da _id olarak kullanabileceğiniz bir anahtarınızın olması gerekir.
Örneğin, usersbir commentskoleksiyonunuz ve koleksiyonunuz olduğunu ve her yorum için bazı kullanıcı demografik bilgileri içeren yeni bir koleksiyonunuz olduğunu varsayalım.
Diyelim ki userskoleksiyonda aşağıdaki alanlar var:
Ve sonra commentskoleksiyon aşağıdaki alanlara sahiptir:
Bu haritayı yaparsınız / azaltırsınız:
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
Bu noktada, users_commentsbirleştirilmiş verileri içeren yeni bir koleksiyonunuz olacak ve şimdi bunu kullanabilirsiniz. Bu azaltılmış koleksiyonların hepsinde _id, harita işlevlerinizde yayınladığınız anahtar vardır ve daha sonra tüm değerler valueanahtarın içinde bir alt nesnedir - değerler bu azaltılmış belgelerin en üst düzeyinde değildir.
Bu biraz basit bir örnek. İndirgenmiş koleksiyonu oluşturmaya devam etmek için daha fazla koleksiyonla bunu tekrarlayabilirsiniz. Süreçteki verilerin özetleri ve toplamalarını da yapabilirsiniz. Büyük olasılıkla, mevcut alanları birleştirme ve koruma mantığı daha karmaşık hale geldiğinden, birden fazla azaltma işlevi tanımlayabilirsiniz.
Ayrıca, her kullanıcının bir dizideki tüm yorumlarını içeren bir belge olduğunu da göreceksiniz. Bire çok değil, bire bir ilişkisi olan verileri birleştiriyor olsaydık, düz olurdu ve basitçe şöyle bir azaltma işlevi kullanabilirsiniz:
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_commentsKoleksiyonu, yorum başına bir belge olacak şekilde düzleştirmek istiyorsanız , ayrıca şunu da çalıştırın:
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"});
Bu teknik kesinlikle anında gerçekleştirilmemelidir. Birleştirilen verileri periyodik olarak güncelleyen bir cron işi veya bunun gibi bir şey için uygundur. Muhtemelen ensureIndexona karşı gerçekleştirdiğiniz sorguların hızlı bir şekilde çalıştığından emin olmak için yeni koleksiyonda yayınlamak isteyeceksiniz (verilerinizin hala bir valueanahtarın içinde olduğunu unutmayın , bu nedenle comments_with_demographicsyorum createdzamanını dizine ekleyecekseniz ,db.comments_with_demographics.ensureIndex({"value.created": 1});
users_commentsilk kod bloğundan sonra koleksiyonda neler var gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835
MongoDB 3.2 artık birden çok koleksiyondaki verileri $ lookup aggregation aşamasında bir araya getiriyor . Pratik bir örnek olarak, iki farklı koleksiyona ayrılmış kitaplar hakkında verileriniz olduğunu varsayalım.
booksAşağıdaki verilerle adlandırılan ilk koleksiyon :
{
"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"
}
Ve ikinci koleksiyon denir books_selling_data, aşağıdaki verilere sahiptir:
{
"_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
}
Her iki koleksiyonu birleştirmek sadece $ lookup komutunu şu şekilde kullanmakla ilgilidir:
db.books.aggregate([{
$lookup: {
from: "books_selling_data",
localField: "isbn",
foreignField: "isbn",
as: "copies_sold"
}
}])
Bu toplama işleminden sonra bookskoleksiyon aşağıdaki gibi görünecektir:
{
"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
}
]
}
Birkaç şeye dikkat etmek önemlidir:
books_selling_dataGönderen " koleksiyonu, bu durumda , parçalanamaz.Sonuç olarak, her iki koleksiyonu da birleştirmek istiyorsanız, bu durumda, satılan toplam kopya ile düz bir copy_s_sold alanı elde etmek istiyorsanız, muhtemelen biraz daha fazla çalışmanız gerekecek, muhtemelen, olmak dışarı $ nihai koleksiyonuna.
$lookuptüm "localField" ve "foreignField" eşit "isbn" olmamalı? "_id" ve "isbn" değil mi?
Mongodb'a toplu ekleme yoksa, içindeki tüm nesneleri döngüye sokar small_collectionve bunları tek tek ekleriz big_collection:
db.small_collection.find().forEach(function(obj){
db.big_collection.insert(obj)
});
$ Lookup ile çok temel bir örnek.
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 }}
])
İşte kullanılır
{ $unwind: { path: "$userInfoData", preserveNullAndEmptyArrays: true }},
{ $unwind: { path: "$userRoleData", preserveNullAndEmptyArrays: true }}
Onun yerine
{ $unwind:"$userRoleData"}
{ $unwind:"$userRoleData"}
Çünkü {$ çile çözme: "$ userRoleData"} eşleşen kaydı arama $ ile bulursa bu boş veya 0 sonucunu döndürecektir.
MongoDB'de sendikaları 'SQL UNION' tarzında yapmak, tek bir sorguda aramalarla birlikte toplamaları kullanarak mümkündür. İşte ben MongoDB 4.0 ile çalışan test bir örnek:
// 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' } }
]);
İşte nasıl çalıştığının açıklaması:
Bir örneğini aggregatedurumlar o herhangi içinde en az bir belge vardır veritabanınızda toplanması. Veritabanınızın herhangi bir koleksiyonunun boş olmayacağını garanti edemezseniz, veritabanınızda, özellikle birleşim sorguları yapmak için orada olacak tek bir boş belge içeren bir tür 'kukla' koleksiyon oluşturarak bu sorunu çözebilirsiniz.
Boru hattınızın ilk aşamasını yapın { $limit: 1 }. Bu, birincisi dışındaki koleksiyonun tüm belgelerini çıkaracaktır.
Bir $projectsahne alanı kullanarak kalan belgenin tüm alanlarını soyun :
{ $project: { _id: '$$REMOVE' } }Toplamınız artık tek, boş bir belge içeriyor. Bir araya getirmek istediğiniz her koleksiyon için arama ekleme zamanı. Sen kullanabilir pipelinebazı özel filtreleme yapmak alanını veya terk localFieldve foreignFieldboş olarak tüm koleksiyonu eşleşecek.
{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
{ $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
{ $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }Artık şu şekilde 3 dizi içeren tek bir belge içeren bir topluluğunuz var:
{
Collection1: [...],
Collection2: [...],
Collection3: [...]
}
Daha sonra $project, $concatArraystoplama işleciyle birlikte bir sahne alanı kullanarak bunları tek bir dizide birleştirebilirsiniz:
{
"$project" :
{
"Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
}
}Artık tek bir belge içeren ve içinde koleksiyon birliğinizi içeren bir dizinin bulunduğu bir topluluğunuz var. Yapılması gereken , dizinizi ayrı belgelere bölmek için bir $unwindve bir $replaceRootaşama eklemektir :
{ $unwind: "$Union" },
{ $replaceRoot: { newRoot: "$Union" } }Voilà. Artık bir araya getirmek istediğiniz koleksiyonları içeren bir sonuç kümeniz var. Daha sonra daha fazla filtre uygulamak, sıralamak, skip () ve limit () uygulamak için daha fazla aşama ekleyebilirsiniz. Hemen hemen istediğiniz her şeyi.
toplamada birden çok koleksiyon için birden fazla $ araması kullanma
sorgu:
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
}
])
sonuç:
{
"_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, veritabanında bulunan her şeyin üstüne ekleme özelliğine sahiptir, bu nedenle bu davranış iki koleksiyonu birleştirmek için kullanılabilir:
Henüz denemedim, ancak harita / azaltma yaklaşımından daha hızlı performans gösterebilir.
İlk olarak Mongo 4.4, yeni $unionWithbirleştirme aşamasını $groupyeni $accumulatoroperatörüne bağlayarak bu birleştirme bir toplama hattı içinde gerçekleştirebiliriz :
// > 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" } }
$unionWithbelirli bir koleksiyondaki kayıtları zaten toplama hattında bulunan belgeler içinde birleştirir. İki birlik aşamasından sonra, boru hattında tüm kullanıcı, kitap ve film kayıtlarına sahibiz.
Daha sonra , operatörü kullanarak, gruplandıkça belgelerin özel olarak birikmesine izin veren öğeleri kullanarak $groupkaydeder $userve biriktiririz $accumulator:
accumulateArgs.init öğeleri gruplandırdığımızda biriktirilecek durumu tanımlar.accumulateişlevi, bir kayıtla özel bir eylem birikmiş bir devlet inşa etmek için gruplandırılmak yapmak mümkündür. Örneğin, gruplanan öğenin booktanımlanmış alanı varsa, durumun bir bookskısmını güncelleriz .mergeiki iç durumu birleştirmek için kullanılır. Yalnızca parçalanmış kümelerde çalışan toplamalar için veya işlem bellek sınırlarını aştığında kullanılır.Evet şunları yapabilirsiniz: Bugün yazdığım bu yardımcı program işlevini al:
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);
}
)
}
}
Bu işleve istediğiniz sayıda koleksiyon aktarabilirsiniz, ilki hedef olan olacak. Geri kalan tüm koleksiyonlar, hedef koleksiyona aktarılacak kaynaklardır.
Kod pasajı. Nezaket-Bu dahil olmak üzere yığın taşması üzerine birden fazla mesaj.
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();
Bunu uygulama katmanınızda yapmanız gerekir. Bir ORM kullanıyorsanız, diğer koleksiyonlarda bulunan referansları çekmek için ek açıklamalar (veya benzer bir şey) kullanabilir. Ben sadece Morphia ile çalıştı ve @Referenceek açıklama sorgulandığında referans varlık alır, bu yüzden kod kendim yapmaktan kaçınmak mümkün.
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});yeterlidir. Mongo kabuğunu kullanmıyorsanız lütfen kullanılmış sürücünüzü (java, php, ...) belirtin.