Reputation: 75
I have a collection with one document. It looks like this:
words: {
wordOne: ["Cat", "Dog","Fish"],
wordTwo: ["Red", "Blue", "Green"],
wordThree: ["Square","Cirecle","Triangle"]
}
I would like to query the DB to select a random key (wordOne
, wordTwo
or wordThree
) and then return a random word from the array on that key.
So far I've written a query that returns the entire document and then I use JS to select a random key and then a random word. That does work of course but I've read that if you can have the DB do the work, it's better to do it that way. Plus I'm really curious how it would be accomplished.
I'm using Node and mongoose
Upvotes: 2
Views: 551
Reputation: 13103
Alternative solution:
db.collection.aggregate([
{
$project: {
words: {
$reduce: {
input: {
$objectToArray: "$words"
},
initialValue: [],
in: {
$concatArrays: [
"$$value",
{
$map: {
input: "$$this.v",
as: "w",
in: {
key: "$$this.k",
word: "$$w"
}
}
}
]
}
}
}
}
},
{
$unwind: "$words"
},
{
$replaceWith: "$words" // For MongoDB v3.4 $replaceRoot:{newRoot:"$words"}
},
{
$sample: {
size: 1
}
}
])
Upvotes: 1
Reputation: 49955
You can transform all the arrays contatined within words
object by using $reduce, $objectToArray and $concatArrays. This will give you one long array of all strings which can be then passed as a parameter to $unwind to get single word per document. Lastly you can run $sample to get random document:
db.collection.aggregate([
{
$project:{
all: {
$reduce: {
input: { $objectToArray: "$words" },
initialValue: [],
in: { $concatArrays: [ "$$value", "$$this.v" ] }
}
}
}
},
{
$unwind: "$all"
},
{
$project: {
_id: 0,
sampleWord: "$all"
}
},
{
$sample: { size: 1 }
}
])
Upvotes: 1