ドキュメントに含まれる配列内の値でソートする方法について

1,104 views
Skip to first unread message

林田 敦

unread,
Jan 7, 2014, 5:52:46 AM1/7/14
to mongo...@googlegroups.com
MongoDB JPコミュニティの皆様

あけましておめでとうございます。林田です。
本年もどうぞよろしくお願いいたします。

新年早々ではございますが、ソートについて教えてください。
ドキュメントに含まれる配列内の値でソートしたいのですが、可能でしょうか。

例えば、以下のようなドキュメントがあったとします。

ドキュメント1 { array : [ { name : "aaaa", value : 1 }, { name : "bbbb", value : 5 } ] }
ドキュメント2 { array : [ { name : "cccc" } ] } 
ドキュメント3 { array : [ { name : "dddd", value : 3 }, { name : "eeee", value : 1 }, ] }

このとき、array配列内のvalueに対してソートをかけ、以下のような順でドキュメントを取り出したいです。

ドキュメント2(valueなし)
ドキュメント3(value=1,3)
ドキュメント1(value=1,5)

そもそも配列内の値でソートすることが可能なのかどうか、
また、可能な場合はどのようなクエリを投げればよいか、ご教示いただけませんでしょうか。

以上、よろしくお願いいたします。

林田

ショウケン, フジサキ

unread,
Jan 7, 2014, 6:31:21 AM1/7/14
to mongo...@googlegroups.com
林田さん
藤崎です。

ソートの仕様をもう少し明確にすると、他のみなさんも答えやすくなるかと思います。

第一ソートキーは、array配列の中の最小のvalue値
第二ソートキーは、array配列の中の2番目に小さいvalue値
であってますでしょうか?

つまり、このようなドキュメント4、5を追加すると、
ドキュメント4 { array : [ { name : “ffff", value : 2 }, { name : “gggg", value : 3 } ] }

ドキュメント5 { array : [ { name : “hhhh", value : 6 }, { name : “iiii", value : 1 } ] }


このようにソートされる想定ですか?
ドキュメント2(valueなし)
ドキュメント3(value=1,3)
ドキュメント1(value=1,5)


ドキュメント5(value=1,6)

ドキュメント4(value=2,3)


ご存知かもしれませんが、配列内の第一要素の値でソートする場合、クエリーはこのようになります。
db.collection.find().sort({"array.value":1});


しかし、上記のクエリーでは林田さんの望むような結果にはならないので、事前に
"配列内のドキュメントをあるキーに基づいてソートする"
プロセスが必要となります。

という解釈であってますか?

--
藤崎 祥見(フジサキ ショウケン)
Fujisaki, Shoken
syo...@gmail.com
> --
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com (mailto:mongodb-jp+...@googlegroups.com) にメールを送信します。
> このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) にメールを送信してください。
> http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。



玉川 竜司

unread,
Jan 7, 2014, 7:46:57 AM1/7/14
to mongo...@googlegroups.com
玉川です。

あれれ?

配列内の第一要素でのソートは

db.collection.find().sort({“array.0.value":1});

じゃないでしょうか?

単に

db.collection.find().sort({“array.value":1});

としてやれば、配列内の全要素を見てソートしてくれるので、ほぼ林田さんのやりたいことができるかと思います。ちなみにdb.collection.ensureIndex{{“array.value":1});でインデックス張ることもできます。

ただ、例えば昇順で並べたときに、配列内の最小の値が等しい複数のドキュメントのソート順を、それぞれのドキュメント中の2番目に小さい値でソートする(複合キーみたいな感じで)のは、簡単にはいかなさそうですね。

玉川@大阪

2014/01/07 20:31、ショウケン, フジサキ <syo...@gmail.com> のメール:

このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com にメールを送信します。
このグループに投稿するには、mongo...@googlegroups.com にメールを送信してください。

ショウケン, フジサキ

unread,
Jan 7, 2014, 8:17:46 AM1/7/14
to mongo...@googlegroups.com
藤崎です。
玉川さん、つっこみありがとうございます。
間違えていました。

db.collection.find().sort({“array.value":1});
で、配列内の全要素を見てソートしてくれました。

あとは、玉川さんも書いてらっしゃるとおり、最小の値が等しい場合のソートが課題ですね。

--
藤崎 祥見(フジサキ ショウケン)
Fujisaki, Shoken
syo...@gmail.com


On Tuesday, January 7, 2014 at 9:46 PM, 玉川 竜司 wrote:

> 玉川です。
>
> あれれ?
>
> 配列内の第一要素でのソートは
>
> db.collection.find().sort({“array.0.value":1});
>
> じゃないでしょうか?
>
> 単に
>
> db.collection.find().sort({“array.value":1});
>
> としてやれば、配列内の全要素を見てソートしてくれるので、ほぼ林田さんのやりたいことができるかと思います。ちなみにdb.collection.ensureIndex{{“array.value":1});でインデックス張ることもできます。
>
> ただ、例えば昇順で並べたときに、配列内の最小の値が等しい複数のドキュメントのソート順を、それぞれのドキュメント中の2番目に小さい値でソートする(複合キーみたいな感じで)のは、簡単にはいかなさそうですね。
>
> —
> 玉川@大阪
>
> 2014/01/07 20:31、ショウケン, フジサキ <syo...@gmail.com (mailto:syo...@gmail.com)> のメール:
> > 林田さん
> > 藤崎です。
> >
> > ソートの仕様をもう少し明確にすると、他のみなさんも答えやすくなるかと思います。
> >
> > 第一ソートキーは、array配列の中の最小のvalue値
> > 第二ソートキーは、array配列の中の2番目に小さいvalue値
> > であってますでしょうか?
> >
> > つまり、このようなドキュメント4、5を追加すると、
> > ドキュメント4 { array : [ { name : “ffff", value : 2 }, { name : “gggg", value : 3 } ] }
> >
> > ドキュメント5 { array : [ { name : “hhhh", value : 6 }, { name : “iiii", value : 1 } ] }
> >
> >
> > このようにソートされる想定ですか?
> > ドキュメント2(valueなし)
> > ドキュメント3(value=1,3)
> > ドキュメント1(value=1,5)
> >
> >
> > ドキュメント5(value=1,6)
> >
> > ドキュメント4(value=2,3)
> >
> >
> > ご存知かもしれませんが、配列内の第一要素の値でソートする場合、クエリーはこのようになります。
> > db.collection.find().sort({"array.value":1});
> >
> >
> > しかし、上記のクエリーでは林田さんの望むような結果にはならないので、事前に
> > "配列内のドキュメントをあるキーに基づいてソートする"
> > プロセスが必要となります。
> >
> > という解釈であってますか?
> >
> > --
> > 藤崎 祥見(フジサキ ショウケン)
> > Fujisaki, Shoken
> > syo...@gmail.com (mailto:syo...@gmail.com)
> >
> >
> > On Tuesday, January 7, 2014 at 7:52 PM, 林田 敦 wrote:
> >
> > > MongoDB JPコミュニティの皆様
> > >
> > > あけましておめでとうございます。林田です。
> > > 本年もどうぞよろしくお願いいたします。
> > >
> > > 新年早々ではございますが、ソートについて教えてください。
> > > ドキュメントに含まれる配列内の値でソートしたいのですが、可能でしょうか。
> > >
> > > 例えば、以下のようなドキュメントがあったとします。
> > >
> > > ドキュメント1 { array : [ { name : "aaaa", value : 1 }, { name : "bbbb", value : 5 } ] }
> > > ドキュメント2 { array : [ { name : "cccc" } ] }
> > > ドキュメント3 { array : [ { name : "dddd", value : 3 }, { name : "eeee", value : 1 }, ] }
> > >
> > > このとき、array配列内のvalueに対してソートをかけ、以下のような順でドキュメントを取り出したいです。
> > >
> > > ドキュメント2(valueなし)
> > > ドキュメント3(value=1,3)
> > > ドキュメント1(value=1,5)
> > >
> > > そもそも配列内の値でソートすることが可能なのかどうか、
> > > また、可能な場合はどのようなクエリを投げればよいか、ご教示いただけませんでしょうか。
> > >
> > > 以上、よろしくお願いいたします。
> > >
> > > 林田
> > >
> > > --
> > > このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> > > このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com (mailto:mongodb-jp+...@googlegroups.com) (mailto:mongodb-jp+...@googlegroups.com) にメールを送信します。
> > > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> >
> >
> >
> >
> > --
> > このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> > このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com (mailto:mongodb-jp+...@googlegroups.com) にメールを送信します。
> > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
>
> --
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com (mailto:mongodb-jp+...@googlegroups.com) にメールを送信します。

林田 敦

unread,
Jan 8, 2014, 4:09:11 AM1/8/14
to mongo...@googlegroups.com, syo...@gmail.com
玉川さん、藤崎さん

林田です。
ご返答ありがとうございます。

ソートの条件は藤崎さんの仰る通りです。

 1)第一ソートキーは、array配列の中の最小のvalue値   
 2)第二ソートキーは、array配列の中の2番目に小さいvalue値 

玉川さんの方法でソートしたところ、ご指摘の通り、

 1)第一ソートキーは、array配列の中の最小のvalue値

は満たせましたが、

 2)第二ソートキーは、array配列の中の2番目に小さいvalue値

を満たすことができませんでした。この条件を満たすことは不可能なのでしょうか。。


ところで、array配列の中にvalue値が無いハッシュがある場合、
それが最小値としてソートされる仕様のようです。

例えば、以下のようなドキュメントが登録されているとき、

 ドキュメント1
 { array[{"name":"aaaa"}] }
 ドキュメント2
 { array[{"name":"bbbb", "value":1}] }
 ドキュメント3
 { array[ {"name":"cccc"}, {"name":"dddd", "value":2} ] }
 ドキュメント4
 { array[ {"name":"eeee", "value":1}, {"name":"ffff", "value":5} ] }
 ドキュメント5
 { array[ {"name":"gggg", "value":3}, {"name":"hhhh", "value":1} ] }

{array.value : 1}でソートしたところ、

 ドキュメント1(最小value:なし),2(最小value:1),5(最小value:1),4(最小value:1),3(最小value:【2】)

とはならずに、

 ドキュメント1(最小value:なし),(最小value:【なし】),(最小value:1)(最小value:1)(最小value:1)

となりました。
従って、厳密には

 1)第一ソートキーは、array配列の中の最小のvalue値

という条件もまだ満たせていない状況です。他に上手いやり方があるのでしょうか。

以上、よろしくお願いいたします。



2014年1月7日火曜日 22時17分46秒 UTC+9 ショウケン, フジサキ:
> > > このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsub...@googlegroups.com) (mailto:mongodb-jp+unsub...@googlegroups.com) にメールを送信します。
> > > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> >  
> >  
> >  
> >  
> > --  
> > このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> > このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsub...@googlegroups.com) にメールを送信します。
> > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
>  
> --  
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsub...@googlegroups.com) にメールを送信します。

Hiroaki Kubota

unread,
Jan 11, 2014, 11:28:47 PM1/11/14
to mongo...@googlegroups.com
窪田です。

まず
MongoDBの配列インデックス自体として、1ドキュメントに複数の値を紐付ける構造にはなっていないので
林田さんの仕様を満たすインデックスは張れません。

インデックスの構造
 value == undefined : doc1, doc3
  value == 1               : doc2, doc4, doc5

なので、どう頑張ってもインデックスが利用できるクエリーとしては発行できません。

■ 解決案1
玉川さんの提案してくれたクエリーで必要な部分を取り出しておいて、アプリ側で細かいソートをする。

■ 解決案2
Aggregation FWを使う。
インデックスの無い状態からオンデマンドで複雑なクエリーを打って解決する。
当然重くなる

■ 解決案3
データ構造自体を改善する。
MongoShell上で書ける位の小さなもので済みそう
例えば
 - array内の要素のvalueをソートしたものをインデックス用のフィールドとして持っておく。

  ドキュメント3 { array : [ { name : "dddd", value : 3 }, { name : "eeee", value : 1 }, ] }
  は
 ドキュメント3 { for_sort: '1_3', array : [ { name : "dddd", value : 3 }, { name : "eeee", value : 1 }, ] }
 としておく。(文字列にする場合は桁数は合わせておく必要がある)


こんな感じでしょうか。
 


2014年1月8日 18:09 林田 敦 <rinrin0...@gmail.com>:
このグループから退会し、メールの受信を停止するには、mongodb-jp+...@googlegroups.com にメールを送信します。
このグループに投稿するには、mongo...@googlegroups.com にメールを送信してください。

林田 敦

unread,
Jan 13, 2014, 10:10:02 PM1/13/14
to mongo...@googlegroups.com
窪田さん

ご返答ありがとうございます。林田です。

インデックスの構造、参考になりました。ありがとうございます。

頂戴した解決策1および解決策2は、検索時のレスポンスが著しく遅くなりそうですので、
データ登録/更新時にひと工夫する解決策3が最も有効かと思います。

皆様のおかげで、設計を進めることができそうです。ありがとうございました。

林田


2014年1月12日日曜日 13時28分47秒 UTC+9 crumbjp:
> > > このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsubscribe@googlegroups.com) (mailto:mongodb-jp+unsubscribe@googlegroups.com) にメールを送信します。
> > > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
> >  
> >  
> >  
> >  
> > --  
> > このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> > このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsubscribe@googlegroups.com) にメールを送信します。
> > このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) にメールを送信してください。
> > http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> > その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。
>  
> --  
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com (mailto:mongodb-jp+unsubscribe@googlegroups.com) にメールを送信します。
> このグループに投稿するには、mongo...@googlegroups.com (mailto:mongo...@googlegroups.com) にメールを送信してください。
> http://groups.google.com/group/mongodb-jp からこのグループにアクセスしてください。
> その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。




--
このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
このグループから退会し、メールの受信を停止するには、mongodb-jp+unsubscribe@googlegroups.com にメールを送信します。
Reply all
Reply to author
Forward
0 new messages