I'd like to retrieve all documents from a MongoDB collection, where users field is either numeric or a string, consisting of all digits (1, 2, 19, or "4", "19", ...)
I query:
db.getCollection('collection').find(
{
users: { $or : [ { $type: [1, 16, 18, 19] },
{ $regex: /^[0-9]+$/ } ]
}
}
)
... and get the error "Unknown operator $or".
This works:
db.getCollection('collection').find(
{
$or: [
{users: { $type: [1, 16, 18, 19] } },
{users: { $regex: /^[0-9]+$/ }}
]
}
)
Why doesn't the first variant work?
$or must itself contains the field upon which you want to query. Your second query contains the field.
$or :[{field_name:Match_expression},{field_name:Match_expression}...{field_name:Match_expression}]
db.getCollection('collection').find( {
$and : [
{ $or : [ { $type: [1, 16, 18, 19] } ] },
{ $or : [ {users: { $regex: /^[0-9]+$/ } ] }
]
} )
this should work
EDIT
This is where it was answered before
Related
I have the following type of document where I have to find instock elements based on a given value. i.e Return all instocks where ele = 5.
{"item":"journal",
"instock":[
{ "warehouse":"A", "ele":[2,4,5] },
{ "warehouse":"C", "ele":[8,5,2] },
{ "warehouse":"F", "ele":[3] },
{ "warehouse":"K", "ele":[2,8,4] }
]
}
I tried to use $elemMatch but it just produces the first element.
db.inventory.find({"item": "journal"}, {"_id": 0, "item": 0, "instock":{$elemMatch: {"ele": {$in: [5]}}} })
But it just gives:
{ "instock" : [
{ "warehouse" : "A", "ele" : [ 2, 4, 5 ] }
]}
And the expectation is
{ "instock" : [
{ "warehouse" : "A", "ele" : [ 2, 4, 5 ] },
{ "warehouse" : "C", "ele" : [ 8, 5, 2 ] }
]}
How should I get the expected result?
The $elemMatch or instock.$ will return first match document in find()'s projection,
You can use aggregation expression in projection from MongoDB 4.4, for your example use array $filter operator in projection,
db.collection.find({
"item": "journal"
},
{
instock: {
$filter: {
input: "$instock",
cond: { $in: [5, "$$this.ele"] }
}
}
})
Playground
For the old version you can use aggregate() using above same operator.
I suggest you to unwind the instock array, then filter the data, and finally if you want you can group the result by item to obtain the desired result.
Here is an exemple: solution
The Problem: I have mongoDB that uses a csv archive that has a
"metrictimestamp" field, but the field is filled with a integer like :
20180201025934, I need a way to put some "/" between the numbers so I can convert
the string to date type, something like: "2018/02/01 02:59:34"
On MongoDB v4.2 or above you can run an aggregation pipeline in updates. So we can get the $substr's of given string & concat all of these substrings & write result to same field, try below query :
db.collection.update( /** Instead of .update() you can use .updateMany() */
{},
[
{ $addFields :{ metrictimestamp :{ $toString : '$metrictimestamp' } } },
{
$addFields: {
metrictimestamp: {
$concat: [
{ $substr: ["$metrictimestamp", 0, 4] },
"/",
{ $substr: ["$metrictimestamp", 4, 2] },
"/",
{ $substr: ["$metrictimestamp", 6, 2] },
" ",
{ $substr: ["$metrictimestamp", 8, 2] },
":",
{ $substr: ["$metrictimestamp", 10, 2] },
":",
{ $substr: ["$metrictimestamp", 12, -1] },
],
},
},
},
],{ multi : true }
);
I'm new to mongodb and am unable to figure out if the below is even possible.
Can I store a condition, such as gt, lt, etc., inside a field in a document and then utilize it in a query?
So, given the following documents:
{
title : "testTitle1",
score : 55,
condition : "gt"
}
{
title : "testTitle2",
score : 30,
condition : "lt"
}
And given an inputScore = 75, only testTitle1 document would be returned because 75 is greater than ("gt") 55. The second document would not be returned because it is not less than ("lt") 30.
Any ideas?
Thanks
Yes, you can the params passed to the query is simply an object. You will need to use the mongodb operators unless you want to add additional processing before you send the query.
As an example:
const data = {
title : "testTitle1",
score : 55,
condition : "$gt"
};
const query = {
score: {}
};
query.score[data.condition] = data.score;
console.log(query);
Example with additional operator conversion:
const data = {
title : "testTitle1",
score : 55,
condition : "gt"
};
const query = {
score: {}
};
switch (data.condition) {
case "gt":
query.score["$gt"] = data.score;
break;
case "lt":
query.score["$lt"] = data.score;
break;
}
console.log(query);
if you want pure mongodb query, you can use $expr operator in your query or aggregation.
db.collection.find({
$expr: {
$or: [
{
$and: [
{$eq: ['$condition', 'gt']},
{$gt: [75, '$score']}
]
},
{
$and: [
{$eq: ['$condition', 'lt']},
{$lt: [75, '$score']}
]
}
]
}
})
i hope you get the idea
The query is with aggregation framework. I use the $switch for checking if the conditionhas a gt or lt value and return a trueor false after the inputScore is compared with the score. This compared result matches gives the filter condition to include or reject the input document.
var inputScore = 75;
db.gtlt.aggregate( [
{ $addFields: {
matches: {
$switch: {
branches: [
{
case: { $eq : [ "$condition", "gt" ] },
then: { $cond: [ { $gt: [ inputScore, "$score" ] }, true, false ] }
},
{
case: { $eq : [ "$condition", "lt" ] },
then: { $cond: [ { $lt: [ inputScore, "$score" ] }, true, false ] }
},
],
default: false
}
}
} },
{ $match: { matches: true } },
{ $project: { matches: 0 } }
] )
I have mongodb document with the following data:
amenities[
{
amenity_id:52,
Amenity:"AC"
},
{
amenity_id:23,
Amenity:"Free Parking"
}
]
I want to match each amenity_id element of the array with particular value and return true or false using condition $cond. I used
"$project":{'Free Parking':{'$cond':{'if':{'$in':['amenities.amenityId',[23]]},'then':'True','else':'False'}}
If a document contains amenity_id= 52 then a query has to return False.
It is returning false irrespective of the menityId. The amenity Id could be list hence using $in. How can i test each element ?
Considering your input collection is
[
{
amenities: [
{
_id: 52,
Amenity: "AC"
},
{
_id: 23,
Amenity: "Free Parking"
}
]
}
]
using aggregate pipeline $map
db.collection.aggregate([
{
$project: {
amenites: {
$map: {
input: "$amenities",
as: "item",
in: {
Amenity: "$$item.Amenity",
_id: "$$item._id",
isValid: {
$cond: {
if: {
$eq: [
"$$item._id",
23
]
},
then: true,
else: false
},
}
}
}
}
}
}
])
You'll get result as:
[
{
"amenites": [
{
"Amenity": "AC",
"_id": 52,
"isValid": false
},
{
"Amenity": "Free Parking",
"_id": 23,
"isValid": true
}
]
}
]
use $unwind operation in mongodb it will unwind the array field in to multiple documents
Please refer this url - https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/
ex:
{
_id :1,
field: [1,2,3]
}
this will be converted to the following using $unwind,
[
{_id, field:1},
{_id, field:2},
{_id, field:3}
]
after $unwind you can run a match query, with $in query,
Ex:
{
$match: {
field: {$in: [1,2]}
}
}
I'm using MongoDB and i have the following schema of person collection:
Person {
age: [number]
}
i want to check if the age of a person exist in array, for exemple [15, 20, 12, 0]. i need something like $in operator but in reverse.
schema:
initiatives : {
ressources: [
{ departement: ObjectId }
{ departement: ObjectId }
]
)
You can use $expr with $in:
Person.find({ $expr: { $in: [ "$age", [15, 20, 12, 0] ] } })
EDIT: to compare arrays you need $setIntersection and $size operators, try:
Person.find({
$expr: {
$gt: [
{
$size: {
$setIntersection: [
[
"15",
"a",
"12",
"0"
],
"$age.x"
]
}
},
0
]
}
})