Использование $ nin и $ sample с агрегацией mongdb

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

Однако я пытаюсь сделать это так, чтобы в возвращаемых песнях не было повторяющихся песен, что я пытаюсь сделать, вставляя значение _id каждой песни в массив по мере его возврата, а затем используя $ nin в этап агрегирования $ match.

var getSongs = function(number, year, db, callback) {
  var collection = db.collection('songsList');
  var songIds = [];
  var chartSongs = [];
  for (var i = 0; i < number; i++) {
    // Get one random document from the collection.
    collection.aggregate([
    {
      $match: { '_id': { '$nin': songIds }, 'songYear': year }
    },
    {
      $sample: { size: 1 }
    }
    ],
    function(err, chart) {
      songIds.push(chart[0]._id);
      chartSongs.push(chart[0]);
      if (songIds.length === number) {
        callback(chartSongs);
      }
    })
  }
};

Однако, хотя мне возвращается правильное количество песен, я все равно получаю повторяющиеся песни в этом случайном списке.

Если кто-нибудь может предложить предложение или даже предложить мне лучший способ сделать это, я был бы очень признателен.


person ebenezer66    schedule 11.04.2016    source источник


Ответы (1)


Как насчет этого?

var getSongs = function(number, year, db, callback) {
  var collection = db.collection('songsList');
  collection.aggregate([                                                                                         
  {
    $match: { 'songYear': year } 
  },
  {
    $sample: { size: number } 
  }
  ],
  function(err, charts) { 
      callback(charts);
  });
};
person hankchiutw    schedule 11.04.2016
comment
Вот с чего я начал. К сожалению, хотя это даст мне определенное количество результатов, это не даст мне уникальных результатов - из документации MongoDB: «$ sample может выводить один и тот же документ более одного раза в своем наборе результатов». Я думал, что итерация $ sample для количества результатов, которые мне нужны, и отправка каждого результата _id в массив для проверки на $ nin должны сработать, но это не для меня. Спасибо, в любом случае. - person ebenezer66; 11.04.2016
comment
@ ebenezer66 Где вы читаете эту цитату из документации? Фактическое поведение задокументировано по этой ссылке. Я думаю, вы запутались с документацией из mapReduce и действием функции reducer. - person Neil Lunn; 12.04.2016
comment
Он находится по предоставленной вами ссылке в большом красном поле с предупреждением в нижней части раздела поведения. Тем не менее, я признаю, что простое использование $ sample size без всей замысловатой ерунды, похоже, дает мне неповторяющиеся результаты. Вчера мог бы сэкономить час или два. - person ebenezer66; 12.04.2016
comment
@ ebenezer66 Я думаю, вы просто не понимаете, что означает изоляция курсора , и вы должны были прочитать ссылку на этот раздел в документации. Все дело в том, что документ действительно нужно будет изменить в процессе извлечения документов из курсора таким образом, чтобы он перемещался по диску и, следовательно, увеличивался. Таких случаев роста вам действительно следует избегать, и, скорее всего, ваше приложение никогда с этим не столкнется. - person Blakes Seven; 13.04.2016
comment
@ ebenezer66 Базовые шансы при относительно небольшом размере выборки будут в основном ничтожными. В любом случае, случайность, безусловно, намного выше, чем ваша собственная попытка просто захватить по одной случайности за раз, что имело бы гораздо более высокую вероятность столкновения. Таким образом, здесь применяется преждевременная оптимизация, и простой процесс выбора n в аргументе $sample, как предлагается, является лучшим подходом. - person Blakes Seven; 13.04.2016