Meteorを使用して、同じサーバー側データベースコレクションを共有するさまざまなクライアント側コレクションを処理するのに最適な方法を考えています。次の例を考えてみましょう。User
コレクションがあり、クライアント側に友達であるユーザーのリストがあり、クエリを実行する検索機能があります。ユーザーデータベース全体、クエリに一致するユーザー名のリストを返します。
サーバー側のPublishメソッドで、同じコレクションに対して2つのクエリがあり、異なるドキュメントのセットが返されます。このデータは、クライアント側の2つの別々のコレクションに入れる必要がありますか?または、両方のクエリに一致するすべてのユーザードキュメントを同じコレクションに含める必要がありますか?後者の場合、サーバー側とクライアント側の両方のクエリに使用されるコードを複製しますか?
サーバー上:
Meteor.publish('searchResults', function(query){
var re = new RegExp(query, 'i')
return Users.find({ 'name' : {$regex: re}})
})
クライアントの場合:
Session.set('searchQuery', null)
Meteor.autosubscribe(function(){
Meteor.subscribe('searchResults', Session.get('searchQuery'))
})
Template.search.events = {
'keyup #user-search' : function(e){
Session.set('searchQuery', e.target.value)
}
}
_.extend(Template.search, {
searchResults: function() {
var re = new RegExp(Session.get('searchQuery'), 'i')
return Users.find({ 'name' : {$regex: re}})
}
})
これはもっともらしい解決策のように見えますが、最適な解決策ではありません。複数のサーバー側コレクションからの検索結果で構成される新しいクライアント側コレクションを作成したい場合はどうなりますか?
共有エリア:
function getSearchUsers(query) {
var re = new RegExp(query, "i");
return Users.find({name: {$regex: re}});
}
function getFriendUsers() {
return Users.find({friend: true}); // or however you want this to work
}
サーバー上:
Meteor.publish("searchUsers", getSearchUsers);
Meteor.publish("friendUsers", getFriendUsers);
クライアントの場合:
Template.search.onCreated(function () {
var self = this;
self.autorun(function () {
self.subscribe("searchUsers", Session.get("searchQuery"));
});
});
Template.friends.onCreated(function () {
this.subscribe("friendUsers");
});
Template.search.helpers({
searchResults: function () {
return getSearchUsers(Session.get("searchQuery"));
}
});
Template.friends.helpers({
results: function () {
return getFriendUsers();
}
});
これからの重要なポイントは、データがネットワークを介して転送されているときに舞台裏で何が起こるかが明らかではないということです。 Meteorはcombineサーバー上のさまざまなクエリで一致したレコードを表示し、これをクライアントに送信します。次に、同じクエリを再度実行してそれらを分割するのはクライアントの責任です。
たとえば、サーバー側のコレクションに20個のレコードがあるとします。次に、2つの公開があります。最初の一致は5レコード、2番目の一致は6で、そのうち2つは同じです。 Meteorは9つのレコードを送信します。次に、クライアントで、サーバーで実行したのとまったく同じクエリを実行すると、それぞれ5レコードと6レコードになります。
私はパーティーに少し遅れていますが、実際には1つのサーバーコレクションのサブセットに対してクライアントに個別のコレクションを用意する方法があります。この例では、entities
とpolygons
に関する情報を保持するrectangles
というサーバーコレクションがあります。
共有コード(libフォルダー):
_// main collection (in this example only needed on the server
Entities = new Meteor.Collection('entities');
// partial collections
RectEntities = new Mongo.Collection('rectEntities');
PolyEntities = new Mongo.Collection('polyEntities');
_
クライアントコード:
_// this will fill your collections with entries from the Entities collection
Meteor.subscribe('rectEntities');
Meteor.subscribe('polyEntities');
_
サブスクリプションの名前はパブリケーションの名前と一致する必要があることに注意してください(コレクション自体の名前ではありません)。
サーバーコード:
_Meteor.publish('rectEntities', function(){
Mongo.Collection._publishCursor( Entities.find({shapeType: 'rectangle'}), this, 'rectEntities');
this.ready();
});
Meteor.publish('polyEntities', function(){
Mongo.Collection._publishCursor( Entities.find({shapeType: 'polygon'}), this, 'polyEntities');
this.ready();
});
_
_publishCursor()
を使用したはるかに簡単なソリューションを提供してくれたuser728291に感謝します!_publishCursor()
関数の3番目の引数は、新しいコレクションの名前です。
出典: http://docs.meteor.com/#/full/publish_added
使用 publish-composite パッケージ
// main collection
Entities = new Meteor.Collection('entities');
// partial collections only client side
RectEntities = new Mongo.Collection('rectEntities');
PolyEntities = new Mongo.Collection('polyEntities');
// server publish
Meteor.publishComposite("rectEntities", function(someParameter) {
return {
collectionName:'rectEntities',
find: function() {
return Entities.find({shapeType: 'rectangle'});
},
children: []
}
});
Meteor.publishComposite("polyEntities", {
collectionName:'polyEntities',
find: function() {
return Entities.find({shapeType: 'polygon'});
},
children: []
});