In my NodeJs application where I am using MongoDb database and I have two collections products and market_companies both collections have a field name hub_id and dimensions here dimensions is an object field.I have created the aggregation pipeline where in both the collections I am comparing hub_id and dimensions field but here the thing is hub_id in products collection is an integer but in market_companies its an string due to which I am not getting desired output.
I want to know how can I convert hub_id to integer from string in market_companies collection.
Below is my code:
db.products.aggregate([
{
$lookup: {
from: "market_companies",
let: {
hubId: "$hubId",
dimensions: "$dimensions"
},
as: "companies",
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$hubId", // How to convert this into Integer
"$$hubId"
]
},
{
$setEquals: [
{
"$objectToArray": {
$ifNull: [
"$dimensions",
{}
]
}
},
{
"$objectToArray": {
$ifNull: [
"$$dimensions",
{}
]
}
}
]
}
]
}
}
},
]
}
}
])
Someone let me know any help appreciated.
You can do it with $toInt operator:
{
$eq: [
{ $toInt: "$hubId" },
"$$hubId"
]
},
Related
I have the following collection
{
"_id" : ObjectId("57315ba4846dd82425ca2408"),
"myarray" : [
{
userId : "8bc32153-2bea-4dd5-8487-3b65e3aa0869",
Time:2022-09-20T04:44:46.000+00:00,
point : 5
},
{
userId : "5020db46-3b99-4c2d-8637-921d6abe8b26",
Time:2022-09-20T04:44:49.000+00:00
point : 2
},
]
}
These are my questions
I want to push into myarray if userId doesn’t exist, and if userid already exists then update time and point also I have to keep only 5 elements in the array if 6th element comes then I a have to sort the array based on Time and remove oldest time entry
what is the best way to do this in mongo using aggregation
FYI we are using Mongo 4.4
You can achieve this by using the aggregation pipeline update syntax, the strategy will be first to update the array (or insert a new element to it).
then if the size exceeds 5 we just filter it based on minimum value. like so:
const userObj = {point: 5, userId: "12345"};
db.collection.updateOne(
{ ...updateCondition },
[
{
$set: {
myarray: {
$cond: [
{
$in: [
userObj.userId,
{$ifNull: ["$myarray.userId", []]}
]
},
{
$map: {
input: "$myarray",
in: {
$cond: [
{
$eq: [
"$$this.userId",
userObj.userId
]
},
{
$mergeObjects: [
"$$this",
{
Time: "$$NOW", // i used "now" time but you can swap this to your input
point: userObj.point
}
]
},
"$$this"
]
}
}
},
{
$concatArrays: [
{ $ifNull: ["$myarray", []] },
[
{
userId: userObj.userId,
point: userObj.point,
Time: "$$NOW"
}
]
]
}
]
}
}
},
{
$set: {
myarray: {
$cond: [
{
$gt: [
{
$size: "$myarray"
},
5
]
},
{
$filter: {
input: "$myarray",
cond: {
$ne: [
"$$this.Time",
{
$min: "$myarray.Time"
}
]
}
}
},
"$myarray"
]
}
}
}
])
Mongo Playground
Hi i am trying to use MONGODB query inside TIBCO jasperstudio to create a report
What I am trying to do is filter the data using two parameters #orderitemuid and #ordercatuid. My case is if I put a parameter using #orderitemuid, it will disregard the parameter for #ordercatuid. Vise versa, if I put a parameter using #ordercatuid, it will disregard the parameter for #orderitemuid. But there is also an option when using bot parameters in the query. I used a $switch inside the $match but I am getting an error. Below is the $match I am using
{
$match: {
$switch: {
branches: [
{
case: { $eq: [{ $IfNull: [$P{orderitemuid}, 0] }, 0] },
then: { 'ordcat._id': { '$eq': { '$oid': $P{ordercatuid} } } },
},
{
case: { $eq: [{ $IfNull: [$P{ordercatuid}, 0] }, 0] },
then: { '_id': { '$eq': { '$oid': $P{orderitemuid} } } },
},
],
default: {
$expr: {
$and: [
{ $eq: ['_id', { '$oid': $P{orderitemuid} }] },
{ $eq: ['ordcat_id', { '$oid': $P{ordercatuid} }] },
],
},
},
},
},
}
Thank you in advance
As mentioned in the $match docs
$match takes a document that specifies the query conditions. The query syntax is identical to the read operation query syntax; i.e. $match does not accept raw aggregation expressions. ...
And $switch is an aggregation expressions. this means it cannot be used in a $match stage without being wrapped with $expr.
You can however wrap it with $expr, this will also require you to restructure the return values a little bit, like so:
db.collection.aggregate([
{
$match: {
$expr: {
$switch: {
branches: [
{
case: {
$eq: [
{
$ifNull: [
$P{orderitemuid},
0
]
},
0
]
},
then: {
$eq: [
"$ordcat._id",
{"$oid":$P{ordercatuid}}
]
}
},
{
case: {
$eq: [
{
"$ifNull": [
$P{ordercatuid},
0
]
},
0
]
},
then: {
$eq: [
"$_id",
{"$oid":$P{orderitemuid}}
]
}
}
],
default: {
$and: [
{
$eq: [
"$_id",
{"$oid": $P{orderitemuid} }
]
},
{
$eq: [
"$ordcat_id",
{"$oid": $P{ordercatuid}}
]
}
]
}
}
}
}
}
])
Mongo Playground
I have a class model which has field ref.
I'm trying to fetch only records that match the condition in lookup.
so what i did:
{
$lookup: {
from: 'fields',
localField: "field",
foreignField: "_id",
as: 'FieldCollege',
},
},
{
$addFields: {
"FieldCollege": {
$arrayElemAt: [
{
$filter: {
input: "$FieldCollege",
as: "field",
cond: {
$eq: ["$$field.level", req.query.level]
}
}
}, 0
]
}
}
},
The above code works fine and returning the FieldCollege if the cond is matched.
but the thing is, i wanted to return the class records only if the FieldCollege is not empty.
I'm totally new to mongodb. so i tried something like this:
{
$match: {
'FieldCollege': { $exists: true, $ne: [] }
}
},
Obv this didn't work.
does mongodb support something like this or am i complicating things?
EDIT:
the result from the above code:
"Classes": [
{
"_id": "613245664c6ea614e001fcef",
"name": "test",
"language": "en",
"year_cost": "3232323",
"FieldCollege":[] // with $unwind
}
],
expected Result:
"Classes": [
// FieldCollege is empty
],
I think the good option is to use lookup with pipeline, and see the final version of your query,
$lookup with fields collection and match your both conditions
$limit to result one document
$match FieldCollege is not empty []
$addElemAt to get first element from result FieldCollege
[
{
$lookup: {
from: "fields",
let: { field: "$field" },
pipeline: [
{
$match: {
$and: [
{ $expr: { $eq: ["$$field", "$_id"] } },
{ level: req.query.level }
]
}
},
{ $limit: 1 }
],
as: "FieldCollege"
}
},
{ $match: { FieldCollege: { $ne: [] } } },
{
$addFields: {
FieldCollege: { $arrayElemAt: ["$FieldCollege", 0] }
}
}
]
I'm using mongoDB and I have documents similar to the following
{
"files": ["Customers", "Items", "Contacts"],
"counts": [1354, 892, 1542],
...
}
And using an aggregation pipeline stage, I want to convert the above into something more like..
{
"file_info": [
{"file_name": "Customers", "record_counts": 1354},
{"file_name": "Items", "record_counts": 892},
{"file_name": "Contacts", "record_counts": 1542}
]
}
I've tried using $map, $reduce, and $arrayToObject but without any success. What operators can I use to get from where I currently am to where I need to be?
You can use $zip to combine two arrays and $map to get the new structure:
{
$project: {
file_info: {
$map: {
input: { $zip: { inputs: [ "$files", "$counts" ] } },
in: {
file_name: { $arrayElemAt: [ "$$this", 0 ] },
record_counts: { $arrayElemAt: [ "$$this", 1 ] },
}
}
}
}
}
Mongo Playground
As part of an aggregate I need to run this transformation:
let inheritances = await db.collection('inheritance').aggregate([
{ $match: { status: 1 }}, // inheritance active
{ $project: { "_id":1, "name": 1, "time_trigger": 1, "signers": 1, "tree": 1, "creatorId": 1, "redeem": 1, "p2sh": 1 } },
{ $lookup:
{
from: "user",
let: { creatorId: { $concat: [ "secretkey", { $toString: "$creatorId" } ] }, time_trigger: "$time_trigger"},
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$_id", sha256( { $toString: "$$creatorId" } ) ] },
{ $gt: [ new Date(), { $add: [ { $multiply: [ "$$time_trigger", 24*60*60*1000 ] }, "$last_access" ] } ] },
]
}
}
},
],
as: "user"
},
},
{ $unwind: "$user" }
]).toArray()
creatorId comes from a lookup, and in order to compare it to _id I first need to do a sha256.
How can I do it?
Thanks.
External functions will not work with the aggregation framework. Everything is parsed to BSON by default. It is all basically processed from BSON operators to native C++ code implementation, This is by design for performance.
Basically in short, you can't do this. I recommend just storing the hashed value on every document as a new field, otherwise you'll have to do it in code just before the pipeline.