SORU
15 NİSAN 2011, Cuma


MongoDB: nasıl..bir tane birden fazla koleksiyon verileri Birleştirmek?

Nasıl (MongoDB) bir koleksiyon içinde birden çok koleksiyon verileri birleştirebilir miyim?

Öyleyse nasıl eğer harita-azaltın kullanabilir miyim?

Bir acemi olduğum gibi büyük ölçüde bazı örnek seviniriz.

CEVAP
5 Ocak 2012, PERŞEMBE


Ancak bunu yapamazsın, gerçek zamanlı, çalışma göster-azaltmak için birden çok kez birleştirme verileri birlikte kullanarak "azaltmak" seçeneği MongoDB 1.8 göster/azaltmak (http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-Outputoptions). Bir _ıd olarak kullanabileceğiniz her iki koleksiyon bazı önemli olması gerekir.

Örneğin, diyelim ki users toplama ve comments bir koleksiyonu var ve her yorum için bazı kullanıcı demografik bilgileri içeren yeni bir koleksiyon var.

Hadi users toplama aşağıdaki alanları vardır ki:

  • _ıd
  • ad
  • soyad
  • ülke
  • cinsiyet
  • yaş

Ve sonra comments toplama aşağıdaki alanlar vardır:

  • _ıd
  • kullanıcı kimliği
  • yorum
  • yarattı

Bu haritayı küçült/.

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, birleştirilmiş verileri içeren yeni bir koleksiyon users_comments denilen olacak ve artık kullanabilirsiniz. Bu azaltılmış koleksiyonları var _id hangi anahtar olduğunu yayan olarak harita işlevleri ve daha sonra bütün değerler alt-nesne içinde value anahtar değerleri değil üst düzeyinde olan bu düşük belgeler.

Bu biraz basit bir örnektir. Daha koleksiyonları ile bu azaltılmış koleksiyonu kadar bina tutmak için istediğiniz kadar tekrar edebilirsiniz. Ayrıca bu süreçte veri özetleri ve toplamalardan yapabilirsin. Muhtemel ve mevcut alanları toplayarak korumak için mantığı daha karmaşık hale geldikçe, birden fazla işlevi azaltmak tanımlarsınız.

Şimdi de Bir dizide bu kullanıcının tüm yorumları ile her kullanıcı için bir belge olduğunu unutmayın. Eğer bir bire-bir ilişki bire-bir değil çok veri birleştirme olsaydık, düz olacak ve sadece böyle bir fonksiyonu azaltmak 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;
};

Eğer yorum başına bir belge yani users_comments toplama düzleştirmek istiyorsanız, Ayrıca bu çalışma:

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 yapılmamalıdır. Bir cron veya birleştirilmiş verileri düzenli aralıklarla güncelleyen böyle bir şey için uygun değil. Sen muhtemelen kaçmak istiyor ensureIndex yeni koleksiyonu için emin olun sorguları gerçekleştirmek karşılaştırdın hızlı (unutmayın, verileriniz hala içinde bir value anahtar, Yani eğer düşünüyorsanız Endeksi comments_with_demographics yorum created zaman olur db.comments_with_demographics.ensureIndex({"value.created": 1});

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • ChannelRichard

    ChannelRicha

    7 Kasım 2008
  • kndx

    kndx

    11 Mart 2006
  • theavettbrothers

    theavettbrot

    9 ŞUBAT 2007