I try to make a query and i don't know the right way to do this.
The mongo collection structure contains multiples user ID (uid) and i want to make a query that get all datas ("Albums") where the User ID match one of the uid.
I do not know if the structure of the collection is good for that and I would like to know if I should do otherwise.
{
"_id": ObjectId("55814a9799677ba44e7826d1"),
"album": "album1",
"pictures": [
"1434536659272.jpg",
"1434552570177.jpg",
"1434552756857.jpg",
"1434552795100.jpg"
],
"uid": [
"12814a8546677ba44e745d85",
"e745d677ba4412814e745d7b",
"28114a85466e745d677d85qs"
],
"__v": 0
}
I just searched on internet and found this documentation http://docs.mongodb.org/manual/reference/operator/query/in/ but I'm not certain that this is the right way.
In short, I need to know: if I use the right method for the stucture of the collection and the operator "$in" is the right solution (knowing that it may have a lot of "User ID": between 2 and 2000 maximum).
You don't need $in unless you are matching for more than one possible value in a field, and that field does not have to be an array. $in is in fact shorthand for $or.
You just need a simple query here:
Model.find({ "uid": "12814a8546677ba44e745d85" },function(err,results) {
})
If you want "multiple" user id's then you can use $in:
Model.find(
{ "uid": { "$in": [
"12814a8546677ba44e745d85",
"e745d677ba4412814e745d7b",
] } },
function(err,results) {
}
)
Which is short for $or in this way:
Model.find(
{
"$or": [
{ "uid": "12814a8546677ba44e745d85" },
{ "uid": "e745d677ba4412814e745d7b" }
]
},
function(err,results) {
}
)
Just to answer your question, you can use the below query to get the desired result.
db.mycollection.find( {uid : {$in : ["28114a85466e745d677d85qs"] } } )
However, you need to revisit your data structure, looks like its a Many-to-Many problem and you might need to think about introducing a mid collection for that.
Related
I have a mongoose schema that is structured like this:
Schema E = {
_id,
... some fields,
details: [
{
...somefields,
people: [ObjectIds]
}
]
}
First, I have an aggregate query where I am using $geoNear then $match, and then $facet.
After the operations the document that I get is as follows:
estates: [
{
_id,
... some fields,
details: [
{
...somefields,
people: [ObjectIds]
}
],
... other fields
},
... more estate objects
]
],
page: [...some objects]
I have an array called approved which has some object Ids.
I want to filter the page array inside events.details while keeping the rest of the fields intact.
The result I want is as follows:
NOTE: *The field filteredPeople is the array I want after filtering people with approved.
estate: [
{
_id,
... some fields,
details: [
{
...somefields,
filteredPeople: [ObjectIds],
numberOfPeople: Size of people array
}
],
... other fields
},
... more estate objectes
],
page: [...some objects]
This is what I tried doing:
{
"estates": {
"$map": {
"input": "$estates",
"as": "estate",
"in": {
"details": {
"$map": {
"input": "$$estate.details",
"as": "detail",
"in": {
"filteredPeople": {
"$filter": {
"input": "$$detail.people",
"as": "people",
"cond": { "$in": ["$$people", approved] }
}
}
}
}
}
}
}
},
}
But this erases the other fields. The other way is to create a separate field called estatePeople where the result of the $addFields will be stored.
I could then try to merge the two arrays. But I don't have any field to match them as the second estatePoeple array will not have anything but the filteredPeople. So I will then somehow have to merge the two arrays just by the index of the array and where they appear.
Can someone please help me out on how to get the desired document with relatively good performance?
For anyone who has the same problem:
In the end, I was unable to find any way to execute the query that I wanted with reasonable performance.
This schema design is not the optimal way to execute such complicated queries. What I ended up doing was making the details array an object and have separate documents for separate details. And then I made a parent schema that kept reference of the details for the same estate.
You can use reverse referencing or referencing according to the queries that you want to execute.
I am trying to create a CouchDB Mango Query with an index with the hope that the query runs faster. At the moment I have the following Mango Query which returns what I am looking for but it's slow. Therefore, I assume, I need to create an index to make it faster. I need help figuring out how to create that index.
selector: {
categoryIds: {
$in: categoryIds,
},
},
sort: [{ publicationDate: 'desc' }],
You can assume that my documents are let say news articles from different categories. Therefore in each document I have a field that contains one or more categories that the news article belongs to. For that I have an array of categoryIds for each document. My query needs to be optimized for queries like "Give me all news that have categoryId1 in their array of categoryIds sorted by publicationDate". What I don't know how to do is 1. How to define an index 2. What that index should be 3. How to use that index in "use_index" field of the Mango Query. Any help is appreciated.
Update after "Alexis Côté" answer:
If I define the index like this:
{
"_id": "_design/0f11ca4ef1ea06de05b31e6bd8265916c1bbe821",
"_rev": "6-adce50034e870aa02dc7e1e075c78361",
"language": "query",
"views": {
"categoryIds-json-index": {
"map": {
"fields": {
"categoryIds": "asc"
},
"partial_filter_selector": {}
},
"reduce": "_count",
"options": {
"def": {
"fields": [
"categoryIds"
]
}
}
}
}
}
And run the Mango Query like this:
{
"selector": {
"categoryIds": {
"$in": [
"e0bd5f97ac35bdf6893351337d269230"
]
}
},
"use_index": "categoryIds-json-index"
}
It still does return the results but they are not sorted in the order I want by publicationDate. So I am not clear what you are suggesting the solution is.
You can create an index as documented here
In your case, you will need an index on the "categoryIds" field.
You can specify the index using "use_index": "_design/<name>"
Note:The query planner should automatically pick this index if it's compatible.
I have problems putting two $OR operations in one query statement. It ignores the earlier $OR operators and only takes into consideration the last $OR operator in the query. (There is no issue when only one $OR operator is in the query.) Am wondering if I am doing something wrong, if this is possible to achieve using CouchDB, or if there is a way around it. Thank you!
I am running a blockchain on Hyperledger Fabric using CouchDB as the state database. (https://hyperledger-fabric.readthedocs.io/en/release-1.4/couchdb_tutorial.html) I am definitely not seasoned in the workings of CouchDB so I may be slightly ignorant in how it's supposed to behave.
It's sort of complicated but my objects basically "belong" to two owners and companies. I want to perform queries such that when I search for a owner or a company, it searches in two different columns to see the the owner/company exists.
e.g. When I search for Company A, it should search for Company A in both company1_id and company2_id.
Query Statement:
{"selector":{"docType":"object", "owner_id": {"$in": ["owner_id"]},
"$or": [{"company1_id": { "$in": ["company_id_1", "company_id_2"]}},
{"company2_id": { "$in": ["company_id_1", "company_id_2"]}}], "$or":
[{"owner1_id": { "$in": ["owner_id_1", "owner_id_2"]}}, {"owner2_id":
{ "$in": ["owner_id_1", "owner_id_2"]}}],
"object_id":{"$lt":"99999999999"}}, "sort": [{"object_id": "desc"}]}
Expected: Get results that corresponds to the above query
What happened: I get results which ignored the first query, so it returns results which corresponds to the following query:
{"selector":{"docType":"object", "owner_id": {"$in": ["owner_id"]},
"$or": [{"owner1_id": { "$in": ["owner_id_1", "owner_id_2"]}},
{"owner2_id": { "$in": ["owner_id_1", "owner_id_2"]}}],
"object_id":{"$lt":"99999999999"}}, "sort": [{"object_id": "desc"}]}
Yes, it ignores it because it's a standard JSON object, so each key must be unique. You have the same situation with a simpler example:
{
"foo": 123,
"foo": 345,
}
Depending on whether your JSON parser accepts the first or last value, your resulting object will be either { "foo": 123 } or { "foo": 345 }.
The solution is to use another logical layer. In your case, you probably want an $and wrapping your $or conditions:
"$and": [
{ "$or": [ ... ] },
{ "$or": [ ... ] },
]
Let's take this document for example:
{
"id":1
"planet":"earth-616"
"data":[
["wolverine","mutant"],
["Storm","mutant"],
["Mark Zuckerberg","human"]]
}
I created a search index to index the name and type, for example if searched for name:wolverine or type:mutant I'd get the document that has it. But as per my requirement I don't want the whole document, I only want ["wolverine","mutant"] I've created a view that outputs as:
{
"id":1,
"key":"earth-616",
"value":["earth-616","wolverine","mutant"]
}
Then I found out I can query only with keys. (Is it possible to create search indexes on views?, Couldn't find anything in the documentation)
Or should I create views along with the one above like this:
{
"id":1,
"key":"wolverine",
"value":["earth-616","wolverine","mutant"]
}
And
{
"id":,
"key":"mutant"
"value":["earth-616","wolverine","mutant"]
}
This way I can query with keys that I want but I can't seem to partial match keys(Am I missing something?)
If you need the output to be exactly as described then I believe you have to use views, and to support wildcard searches I believe you will have to index every substring of a key.
One alternative is to use Cloudant Query, although admittedly you cannot get the exact output you are looking for. If you issue a query like so:
{
"selector": {
"_id": {
"$gt": 0
},
"data": {
"$elemMatch": {
"$elemMatch": {
"$regex": "(?i)zuck"
}
}
}
},
"fields": [
"data"
]
}
The result will be the entire data array:
{
"data": [
["wolverine", "mutant"],
["Storm", "mutant"],
["Mark Zuckerberg", "human"]
]
}
so in my MongoDB database I have a collection holding user posts.
Within that collection I have a set called "likes", which holds an array of the ids of the users that have liked that post. When querying I would like to pass a user id to my query and have a boolean in the result telling me whether the id exists in the array to see whether the user has already liked the post. I understand this would be easy to do with two queries, one to get the post and one to check if the user has liked it, but I would like to find the most efficient way to do this.
For example, one of my documents looks like this
{
_id: 24jef247jos991,
post: "Test Post",
likes: ["userid1", "userid2"]
}
When I query from "userid1" I would like the return
{
_id: 24jef247jos991,
post: "Test Post",
likes: ["userid1", "userid2"],
userLiked: true
}
But when I query from let's say "userid3" I would like
{
_id: 24jef247jos991,
post: "Test Post",
likes: ["userid1", "userid2"],
userLiked: false
}
You can add the $addFields stage checking each of the document likes arrays against the input user.
db.collection.aggregate( [
{
$addFields: {
"userLiked":{ $in: [ "userid1", "$likes" ] }
}
}
] )
Starting from MongoDB 3.4 you can use the $in aggregation operator to check if an array contains a given element. You can use the $addFields operator aggregation operator to add the newly computed value to your document without explicitly including other fields.
db.collection.aggregate( [
{ "$addFields": { "userLiked": { "$in": [ "userid1", "$likes" ] } } }
])
In MongoDB 3.2, you can use the $setIsSubset operator and the square bracket [] operator to do this. The downside of this approach is that you need to manually $project all the field in your document. Also the $setIsSubset operator with de-duplicate your array which may not be what you want.
db.collection.aggregate([
{ "$project": {
"post": 1, "likes": 1,
"userLiked": { "$setIsSubset": [ [ "userid3" ], "$likes" ] }
}}
])
Finally if your mongod version is 3.0 or older you need to use the $literal operator instead of the [] operator.