пользователи метеора не синхронизируют опубликованные подполя профиля

Работая над своим социальным приложением, я обнаружил странное поведение в коллекции Meteor.users, эта проблема не возникает с другими коллекциями, использующими те же методологии.

Я хотел бы иметь первоначальный список пользователей, загружающих минимальное количество информации для всех, и когда я открываю панель для определенного пользователя, я подписываюсь на другое отображение дополнительной информации, если указанный пользователь является моим другом.

Но после подписки клиентская коллекция Meteor.users не обновляется!

КЛИЕНТ

Meteor.startup(function() {

    Meteor.subscribe('usersByIds', Meteor.user().profile.friends, function() {

        //... make users list panel using minimal fields

    });

    //performed when click on a user
    function userLoadInfo(userId) {

        Meteor.subscribe('userById', userId, function() {

            var userProfile = Meteor.users.findOne(userId).profile;

            //...
            //make template user panel using full or minimal user fields
            //...

            //BUT NOT WORK!

            //HERE Meteor.users.findOne(userId) keep minial user fields!!
            //then if userId is my friend!

        });         
    }
});

СЕРВЕР

//return minimal user fields
getUsersByIds = function(usersIds) {

    return Meteor.users.find({_id: {$in: usersIds} },
                            {
                                fields: {
                                    'profile.username':1,
                                    'profile.avatar_url':1
                                }
                            });
};

//return all user fields
getFriendById = function(userId) {

    return Meteor.users.find({_id: userId},
                            {
                                fields: {
                                    'profile.username':1,
                                    'profile.avatar_url':1
                                    //ADDITIONAL FIELDS                         
                                    'profile.online':1,
                                    'profile.favorites':1,
                                    'profile.friends':1
                                }
                            });
};

//Publish all users, with minimal fields
Meteor.publish('usersByIds', function(userId) {

    if(!this.userId) return null;

    return getUsersByIds( [userId] );
});

//Publish user, IF IS FRIEND full fields
Meteor.publish('userById', function(userId) {

    if(!this.userId) return null;

    var userCur = getFriendById(userId),
        userProfile = userCur.fetch()[0].profile;

    if(userProfile.friends.indexOf(this.userId) != -1)  //I'm in his friends list
    {
        console.log('userdById IS FRIEND');
        return userCur;     //all fields
    }
    else
        return getUsersByIds( [userId] );   //minimal fields
});

person stefcud    schedule 20.03.2014    source источник
comment
Вы уверены, что ваша полная пользовательская подписка вызывается при нажатии кнопки? Вы проверили в своей консоли, чтобы убедиться, что данные отсутствуют? Вы можете использовать .ready() для своей подписки вместо того, чтобы пытаться использовать обратный вызов.   -  person Firo    schedule 21.03.2014
comment
Да, я уверен, что сервер печатает журнал: «userdById IS FRIEND», но коллекция клиентов не обновляется! Я пытался использовать this.ready() внутри публикации, но не работал! :( Я использовал консоль Chrome для тестирования коллекции пользователей Meteor.users.find().fetch().. в клиенте, но данные не обновляются с полными полями!   -  person stefcud    schedule 21.03.2014


Ответы (2)


Это ограничение или ошибка в DDP. См. это.

Обходной путь — переместить данные из users.profile.

Как это:

//limited publish
Meteor.publish( 'basicData', function( reqId ){
  if ( this.userId ) {      

    return Meteor.users.find({_id: reqId },{
      fields: { 'profile.username':1,'profile.avatar_url':1}
    });
  } 
  else {
    this.ready();
  }
});

//friend Publish
Meteor.publish( 'friendData', function( reqId ){
  if ( this.userId ) {

    return Meteor.users.find( {_id: reqId, 'friendProfile.friends': this.userId }, {
      fields: {
        'friendProfile.online':1, 
        'friendProfile.favorites':1,
        'friendProfile.friends':1
      }
    });
  } 
  else {
    this.ready();
  }
});

//example user
var someUser = {
   _id: "abcd",
   profile: {
     username: "abcd",
     avatar_url: "http://pic.jpg"
   },
   friendProfile: {
     friends: ['bcde', 'cdef' ],
     online: true,
     favorites: ['stuff', 'otherStuff' ]
   }
}
person user728291    schedule 21.03.2014
comment
Я уже пробовал этот способ (двойная публикация), но если я запрашиваю до ограниченной публикации и после полной публикации... в Meteor.users (клиент) поля остаются ограниченными! подписка работает(я вижу логи) но в локальных данных сбора нет изменений! Я хочу уточнить, что эта проблема появляется только для коллекции Meteor.users, для другой коллекции это работает! - person stefcud; 21.03.2014
comment
использование .rewind() не меняет поведение :( - person stefcud; 21.03.2014
comment
Посмотрел еще. Это известная ошибка, которая по какой-то причине остается недокументированной — github.com/meteor/meteor/issues. /903. Это не просто пользовательские документы, а любая публикация поддокументов. Таким образом, обходным путем является перемещение некоторых ваших данных из поля профиля. - person user728291; 21.03.2014
comment
@ user728291 Я не думаю, что это ошибка как таковая. Скорее просто сделать протокол менее сложным. - person Firo; 21.03.2014
comment
хорошо, но .. поскольку это не задокументировано, я бы сказал, что это ошибка - person stefcud; 21.03.2014
comment
@user728291 user728291 я вижу ваше редактирование, но я знаю, что проблема сохраняется в подполях внутри friendProfile .. или нет? например, если в БД обновить «friendProfile.online» до 0, клиент не синхронизируется - person stefcud; 21.03.2014
comment
Насколько я понимаю, проблема заключается в том, что только одна функция публикации может управлять подполями для полей, которые она публикует для данного документа. Я думаю, что это связано с различием между «добавлено» и «изменено» внутри публикации, когда клиент получает запутанную информацию, если ему говорят дважды добавить один и тот же документ, а не обновлять уже имеющийся документ. - person user728291; 22.03.2014
comment
Если вы не видите, что обновления опубликованных полей передаются клиенту, это еще одна ошибка, поэтому сделайте упрощенное воспроизведение и зарегистрируйте его на github. Если я использую приведенный выше код и обновляю «friendProfile.online» на сервере, изменения правильно распространяются на клиент. - person user728291; 22.03.2014

Как указано в комментарии, эта ссылка раскрывает вашу проблему. Текущий протокол DDP не позволяет публиковать вложенные документы. Один из способов обойти это — создать отдельную коллекцию с вашими данными, но лучшим способом, вероятно, было бы просто удалить некоторые данные и сделать их прямым объектом вашего пользователя.

Лучший способ сделать это — добавить данные в профиль пользователя при вставке, а затем в onCreateUser переместить данные пользователю напрямую:

Accounts.onCreateUser(function(options, user) {
    if (options.profile) {
        if (options.profile.publicData) {
            user.publicData = options.profile.publicData;
            delete options.profile.publicData;
        }
        user.profile = options.profile;
    }
    return user;
});

Если вы разрешаете клиентам выполнять пользовательские вставки, убедитесь, что вы лучше проверяете данные. Таким образом, вы можете иметь online, favorites и friends в профиле и опубликовать их именно тогда, когда захотите. Затем вы можете иметь username и avatar_url в объекте publicData непосредственно для пользователя и просто всегда публиковать все время.

person Firo    schedule 21.03.2014
comment
интересный способ! Но это вызывает большую проблему... в клиенте Meteor.user() не содержит поля publicData, а только профиль!! Я думаю, что это вызвано тем, что поля по умолчанию отправляются пакетом учетных записей. я не знаю как это решить - person stefcud; 22.03.2014
comment
@StefanoCudini содержит ли сервер объект publicData в корне (поэтому он не вложен в профиль), если вы используете этот подход? - person Firo; 22.03.2014
comment
Я редактирую коллекцию пользователей (перемещаю поля из профиля в publicData), но таким образом у клиента Meteor.user не содержит publicData, а только пустой профиль - person stefcud; 22.03.2014
comment
@StefanoCudini Я понимаю вашу проблему, но проверили ли вы свой mongodb на сервере, чтобы убедиться, что данные вообще сохраняются? - person Firo; 22.03.2014
comment
да, я использую консоль mongo (для сервера) и консоль chrome для клиента, возможно, теперь я решил, используя пользовательскую публикацию curreUser (включая поле publicData и поле профиля для зарегистрированного пользователя - person stefcud; 22.03.2014