How to query with $in with multiple arrays - mongodb

I´m developing a filter system that you can filter a set of tv´s by price, brand and screen size. Now, I´m able to filter the tv´s by brand like follows:
db.tvs.find({brand: {$in: ['LG', 'Samsung']}})
And it works.
But right now, I´d like to do the same but with multiple filters (price and screensize), something like this:
db.tvs.find({brand: {$in: ['LG', 'Samsung']}}, {screensize: {$in: ['37', '42']}})
It is possible?

You didn't have to use $and... You could do it like this:
db.tvs.find({brand: {$in: ['LG', 'Samsung']}, screensize: {$in: ['37', '42']}})
The only difference with
with your version
db.tvs.find({brand: {$in: ['LG', 'Samsung']}}, {screensize: {$in: ['37', '42']}})
is that i did not close the first brackets {} after the brand and didn't open a new one before screensize. You need to have them all in the same bson object
A more simple case to understand is this:
db.tvs.find( {brand : "LG" , screensize : '37'})

I did it.
With the $and operator.
db.tvs.find({ $and: [ { brand: {$in: ["LG", "Samsung"]} },{ size: {$in: ["37"] }}, { price: { $gte: 0 } }, { price: { $lte: 499 } } ] })

You should look into what is happening with you code:
db.tvs.find( { brand: { $in: ['LG', 'Samsung']} } , { screensize: { $in: ['37', '42']}} )
The query you put is some thing like
db.collectionName.find({},{});
Check this docs, It clearly says db.collection.find({<criteria>}, {<projection>}). So your query should be constructed such that it should belong to the first parameter not the <projection>.
In your case as mentioned above, the second query you wanted to make is going as second parameter which is intrepreted as for projection.
The projection parameter specifies which fields to return.
Projection parameter should be constructed as follows:
{'FieldName':1}
Where, 1 for the field to be returned in result otherwise 0 to explicitly excluded.
So coming to the answer you are looking for is as below:
db.tvs.find({brand:{$in: ['LG', 'Samsung']}, screensize: {$in: ['37', '42']}})

Related

MongoDB: Add field to all objects in array, based on other fields on same object?

I am fairly new to MongoDB and cant seem to find a solution to this problem.
I have a database of documents that has this structure:
{
id: 1
elements: [ {elementId: 1, nr1: 1, nr2: 3}, {elementId:2, nr1:5, nr2: 10} ]
}
I am looking for a query that can add a value nr3 which is for example nr2/nr1 to all the objects in the elements array, so that the resulting document would look like this:
{
id: 1
elements: [ {elementId: 1, nr1: 1, nr2: 3, nr3:3}, {elementId:2, nr1:5, nr2: 10, nr3: 2} ]
}
So I imagine a query along the lines of this:
db.collection.updateOne({id:1}, {$set:{"elements.$[].nr3": nr2/nr1}})
But I cant find how to get the value of nr2 and nr1 of the same object in the array.
I found some similar questions on stackoverflow stating this is not possible, but they were 5+ years old, so I thought maybe they have added support for something like this.
I realize I can achieve this with first querying the document and iterate over the elements-array doing updates along the way, but for the purpose of learning I would love to see if its possible to do this in one query.
You can use update with aggregation pipeline starting from MongoDB v4.2,
$map to iterate loop of elements
divide nr2 with nr1 using $divide
merge current object and new field nr3 using $mergeObjects
db.collection.updateOne(
{ id: 1 },
[{
$set: {
elements: {
$map: {
input: "$elements",
in: {
$mergeObjects: [
"$$this",
{ nr3: { $divide: ["$$this.nr2", "$$this.nr1"] } }
]
}
}
}
}
}]
)
Playground
db.collection.update(
{ id:1},
{ "$set": { "elements.$[elem].nr3":elements.$[elem].nr2/elements.$[elem].nr1} },
{ "multi": true }
);
I guess this should work

Filter a find by the last element on an embedded array

In MongoDB how can I do a search that is filtered by a predicate applied on the last element of an embedded array?
I know if I wanted to do it on the first one I could do this:
db.inventory.find( { 'instock.0.qty': { $lte: 20 } } )
As specified on the documentation.
How do I write an analog query that looks at the last element, when I don't know the exact size of the embedded array?
we can use $arrayElemAt and pass -1 to it as a second argument to get the last element in the array
something like this
db.collection.find({
$expr: {
$gt: [
{
$arrayElemAt: ["$instock.qty", -1]
},
10
]
}
})
you can test it here Mongo Playground
hope it helps

Aggregation using Project and Slice, mongodb

I've seen similar questions but far to complex for a newbie like myself. Plus none of the answers offered a syntax break down.
My database:
name :"Kim"
points: [
{ category:"Purchase",
points: -50},
{ category: "Wage",
points : 275},
{ category: "Purchase",
points: -40}
]
name :"Meghan"
points: [
{ category:"Contest",
points: 130},
{ category: "Purchase",
points : -25},
{ category: "Games",
points : 50}
]
]
So in the mongo shell I'm trying to get it find every points.category that equals "Purchase" but only return to me the last one. I attempted to achieve this by using aggregate, $project and $slice. My issue is that I don't understand the syntax well enough to know whether $slice goes inside $project or outside separated by a comma. I understand the syntax when I use $project by itself or $slice by itself but I have no clue how to use all these things together to something magical. If someone could help me solve my problem and explain how to combine all these things properly together, I'd be forever indebted. I've read over the docs but nothing showed me how to use everything all at once.
I want to search the student who's name is Kim points to find the last Purchase she made. The result I want is
[{points:-40}]
If you can use more projection with other aggregation operator, you may try this.
db.students.aggregate([
{ $match : { name : "Kim" } },
{ $project:
{
points: {
$filter : { input: "$points", as:"pts", cond: {$eq: ["$$pts.category", "Purchase"]} }
}
}
},
{ $project:
{
_id : 0,
points: { $arrayElemAt: [{$slice: [ "$points.points", -1]},0] }
}
}
])

MongoDB query to find property of first element of array

I have the following data in MongoDB (simplified for what is necessary to my question).
{
_id: 0,
actions: [
{
type: "insert",
data: "abc, quite possibly very very large"
}
]
}
{
_id: 1,
actions: [
{
type: "update",
data: "def"
},{
type: "delete",
data: "ghi"
}
]
}
What I would like is to find the first action type for each document, e.g.
{_id:0, first_action_type:"insert"}
{_id:1, first_action_type:"update"}
(It's fine if the data structured differently, but I need those values present, somehow.)
EDIT: I've tried db.collection.find({}, {'actions.action_type':1}), but obviously that returns all elements of the actions array.
NoSQL is quite new to me. Before, I would have stored all this in two tables in a relational database and done something like SELECT id, (SELECT type FROM action WHERE document_id = d.id ORDER BY seq LIMIT 1) action_type FROM document d.
You can use $slice operator in projection. (but for what you do i am not sure that the order of the array remain the same when you update it. Just to keep in mind))
db.collection.find({},{'actions':{$slice:1},'actions.type':1})
You can also use the Aggregation Pipeline introduced in version 2.2:
db.collection.aggregate([
{ $unwind: '$actions' },
{ $group: { _id: "$_id", first_action_type: { $first: "$actions.type" } } }
])
Using the $arrayElemAt operator is actually the most elegant way, although the syntax may be unintuitive:
db.collection.aggregate([
{ $project: {first_action_type: {$arrayElemAt: ["$actions.type", 0]}
])

Mixing MongoDB query types (and, or)

I am using MongoDB to store information on coffees and I am having problems with a query.
My document structure is:
{ _id: "Thailand Bok", tags: ["Strong", "Smooth", "Dark"] }
I am trying to create query that allows me to search either on the name or tags.
So given that a query string may be "Thailand Bok" or ["Strong", "Smooth"] I want to search for requests that either contain the _id or each tag.
If I were thinking in SQL terms it may be something like this:
"WHERE `_id` like 'Not present%' OR ("Strong" IN `tags` AND "Smooth" IN `tags`)"
The query I have so far is:
{
$or: [
{ _id: { $regex: '^Not present', '$options': 'i' } },
{
$and: [
{ tags: 'Strong' },
{ tags: 'Smooth' }
]
}
]
}
edit: correct a mistake in the query and clarified that it should work either if the _id matches OR the tags match
$and is only supported in version MongoDB 2.0+ I was using 1.8.2
You query seems allright except for using curly braces instead of square braces for $or.
{$or: [
{_id: {$regex: '^hailand', $options: 'i'} },
{'$and': [
{tags: 'Strong'},
{tags: 'Smooth'}
]}
]}
Works just fine.