我认为我的音乐应用程序的架构设计存在问题。
我有3个集合:Artists
,Tracks
和Albums
。
和3个班级:artists
,albums
和tracks
artists
的文件:
[_id] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
[freeze] => false,
[genres] => Array,
[hits] => 0,
[name] => Sarya Al Sawas,
[pictures] => Array,
来自albums
的文件:
[_id] => MongoId Object
(
[$id] => 4ee88308615c218128000000
)
[name] => Sabia
[slug] => wafiq-habib-ft-sarya-al-sawas-sabia
[year] => 1999
[genres] => Array,
[pictures] => Array,
[artists] => Array
(
[0] => MongoId Object
(
[$id] => 4ee34a3b615c21b624010000
)
[1] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
)
来自tracks
的文件
[_id] => MongoId Object
(
[$id] => 4ee8a056615c21542a000000
)
[name] => Bid Ashok
[slug] => wafiq-habib-ft-sarya-al-sawas-bid-ashok
[genres] => Array,
[file] => /m/tracks/t.4ee8a05540c624.04707814.mp3,
[freeze] => false,
[hits] => 0,
[duration] => 303,
[albums] => Array
(
[0] => MongoId Object
(
[$id] => 4ee5cbc3615c216509000000
)
)
[artists] => Array
(
[0] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
[1] => MongoId Object
(
[$id] => 4ee34a3b615c21b624010000
)
)
首先是好的架构设计??! 我以这种方式设计了这个模式,因为有很多关系 有时候曲目有2位艺术家,而专辑有2位艺术家。
无论如何,我在查询附加到特定曲目的专辑时遇到问题。
让我说我在艺术家页面
我需要获取所有艺术家专辑和曲目,所以我这样做:
$cursors = array(
'albums' => $this->albums->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
'tracks' => $this->tracks->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
'clips' => $this->clips->find(array('artists' => $artist->_id))->sort(array('_id' => -1))
);
foreach($cursors as $key => $cursor) {
foreach($cursor as $obj) {
$obj['name'] = ($this->lang->get() != 'ar' ? $obj['translated']['name'] : $obj['name']);
$obj['by'] = $this->artists()->get($obj['artists'])->toString('ft');
${$key}[] = $obj;
}
}
我需要在所有曲目上循环并获取他们的专辑名称,让我们说这位艺术家有3000首曲目 我认为这会很慢......
所以我的问题是:这是一个很好的架构设计吗?
答案 0 :(得分:3)
嗯,这是一个非常关系的问题,使用非关系型数据库来解决这个问题需要付出一些努力。一般来说,我认为您的架构设计很好。
你所描述的被称为“N + 1问题”,因为你必须对N个对象进行N + 1个查询(在你的情况下,它更复杂,但我想你明白了)。
一些补救措施:
您可以使用$in
运算符查找例如某位艺术家的所有曲目:
db.tracks.find({"artists" : { $in : [artist_id_1, artist_id_2, ...] } });
如果艺术家阵容变得庞大,这不起作用,但是几百,也许一千个应该可以正常工作。确保已将artists
编入索引。
您可以经常对所需的一些信息进行反规范化。例如,您可能希望经常显示曲目列表,因此将艺术家的名称复制到每个曲目是有意义的。非规范化主要取决于您从最终用户角度尝试实现的目标。您可能不想完整地存储每个艺术家的名字,但只想存储前50个字符,因为UI无论如何都不会在概述中显示更多。
事实上,你已经对某些数据进行了非规范化处理,例如专辑中的艺术家ID(这些数据是多余的,因为你也可以通过曲目获取它们)。这使得查询更容易,但是它会更加繁重。更新很难看,因为你必须确保它们在系统中传播。
在某些情况下,在客户端(!)而不是服务器上“加入”可能是有意义的。这不太适合你的问题,但值得注意的是:假设你有一个朋友列表。现在,服务器必须在显示每个朋友的名字时查找它们。相反,它可以为您提供查找表ID /朋友,服务器只提供ID。有些JavaScript可以用客户端缓存中的真实名称替换id。