MongoDB: Regroup by two field with different value - node.js

I created a nodejs app in Typescript.
I want to group documents by two fields "one_id" and "two_id" with specified one_id value.
Here is my data in my collection:
{
"_id":"5a8b2953007a1922f00124fd",
"one_id":"307973260186877954",
"two_id":"415228402765660181"
}
{
"_id":"5a8b29a3007a1922f00124fe",
"one_id":"415228402765660181",
"two_id":"307973260186877954"
}
{
"_id":"5a8c119bf6ba49302c3ef67e",
"one_id":"394199132195127306",
"two_id":"270131587092316161"
}
{
"_id":"5a8c11a4f6ba49302c3ef67f",
"one_id":"270131587092316161",
"two_id":"394199132195127306"
}
{
"_id":"5a8c33132a182308a836bc1c",
"one_id":"307973260186877954",
"two_id":"397036401075552256"
}
{
"_id":"5a8c33242a182308a836bc1d",
"one_id":"397036401075552256",
"two_id":"307973260186877954"
}
And if I want to get pairs with one_id="307973260186877954", the excepted result would be: (must have another document with "inversed" fields content)
{
"_id":"5a8b2953007a1922f00124fd",
"one_id":"307973260186877954",
"two_id":"415228402765660181"
}
{
"_id":"5a8b29a3007a1922f00124fe",
"one_id":"415228402765660181",
"two_id":"307973260186877954"
}
{
"_id":"5a8c33132a182308a836bc1c",
"one_id":"307973260186877954",
"two_id":"397036401075552256"
}
{
"_id":"5a8c33242a182308a836bc1d",
"one_id":"397036401075552256",
"two_id":"307973260186877954"
}
I don't know if you understand me.
Thank you, I hope someone will understand me!

You can use $lookup to self join the rows and output the document when there is a match and $project with exclusion to drop the joined field.
db.col.aggregate([
{"$lookup":{
"from":col,
"localField":"one_id",
"foreignField":"two_id",
"as":"onetwo"
}},
{"$lookup":{
"from":col,
"localField":"two_id",
"foreignField":"one_id",
"as":"twoone"
}},
{"$match":{"onetwo.0":{"$exists":true}, "twoone.0":{"$exists":true}}},
{"$project":{"onetwo":0,"twoone":0}}
])

I think this should be your solution. Not sure. Just gave it a try
db.TempCollections.aggregate([
{
$lookup:{
from:"TempCollections",
let:{
leftone_id:"$one_id",
lefttwo_id:"$two_id"
},
pipeline:[
{
$match: {
$expr: {
$and: [
{
$eq: [
"$one_id",
"$$lefttwo_id"
]
},
{
$eq: [
"$two_id",
"$$leftone_id"
]
}
]
}
}
}
],
as:"Final"
}
}
],
{
allowDiskUse:true
});

Related

Update nested object in array MongoDB

I need to find and update documents with category that corresponding to the query. Array could contain mo than one corresponding id.
Query:
{
"ids": ["61f1cda47018c60012b3dd01", "61f1cdb87018c60012b3dd07"],
"userId": "61eab3e57018c60012b3db3f"
}
I got collection with documents like:
`{
"_id":{"$oid":"61f1cdd07018c60012b3dd09"},
"expenses":[
{"category":"61eafc104b88e154caa58616","price":"1111.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"2222.00"},
{"category":"61f1cda47018c60012b3dd01","price":"1241.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"111.00"}
],
"userId":"61eab3e57018c60012b3db3f"
}`
my method:
async myMethod(ids: [string], userId: string) {
try {
const { ok } = await this.ExpensesModel.updateMany(
{"userId": userId, "expenses.category": { $in: ids }},
{$set: {"expenses.$.category": "newCategoryID"}}
);
return ok
} ........
I path array of ids ["61f1cda47018c60012b3dd01","61f1cdb87018c60012b3dd07","61f1cdb87018c60012b3dd07"] and userId, this code update only 1 category by document.
So can i made it with mongo build in methods? or i need to find matching document and update it it by my self and after that update or insert;
Update with arrayFilters
db.collection.update({
"expenses.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
},
{
$set: {
"expenses.$[elem].category": "61eab3e57018c60012b3db3f"
}
},
{
arrayFilters: [
{
"elem.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
}
]
})
mongoplayground

MongoDB updating array of objects does not work as expected

Got multiple documents in a db one of which looks like this:
{
"searchWord":[
"pizz",
"pizza"
],
"result":[
{
"idMeal":1,
"strMeal":"test1",
"strInstructions":"test1"
},
{
"idMeal":2,
"strMeal":"test2",
"strInstructions":"test2"
}
]
}
Tried to solve it like this:
eg:
db.meals.updateOne(
{
"searchWord": "pizz",
"result": { $elemMatch: { idMeal: "1" } }
},
{ $set: { 'result.$.strMeal' : "UPDATED" } }
)
This doesnt update the respective subdocument only the 2nd as if I wrote
{ $set: { 'result.1.strMeal' : "UPDATED" } }
(Which will result in the 2nd subdocument being updated)
This is the other idea (Same result)
db.meals.updateOne(
{ searchWord: "pizz", 'result.idMeal': 319012 },
{ $set: { "result.$.strMeal" : "fsdf" } }
)
What I dont seem to understand is its exactly the syntax that is provided by mongo yet it doesnt work
The "$" operator doesnt pick up which array of objects I wanna update
Try to use $[] in your $set for multiple positional element
db.collection.update({
"searchWord": "pizz"
},
{
$set: {
"result.$[r].strMeal": "UPDATED"
}
},
{
arrayFilters: [
{
"r.idMeal": 1
}
]
})
Here is the Mongo playground for your reference.

set a random values in a field using UpdateMany in mongoose query

I wanted to know whether this is possible that while updating many documents using UpdateMany in mongoose I need to set any of the status value from ["pending", "settled"] to a key called payment_settlement for different documents.
For better understanding I'm adding the route here:
router.post("/payment_settlement", (req, res, next) => {
var ar = ["pending", "settled"];
models.Payment.updateMany({ $set: { payment_settlement: ar[Math.floor(Math.random() * 2)] } })
.then(_ => {
return funcs.sendSuccess(res, _);
})
.catch(next);
});
The above approach gave me the same result for all documents either "pending" or "settled".
My doubt is that MongoDB(Mongoose) computing random value once at the beginning, and using that single random value for all documents.
However, we can achieve this using enum in mongoose schema. But I need to update existing documents with random values.
Any ideas or discussion is highly appreciated.
Thanks
Because you are using mongodb version 4.4.2 so you can use Updates with Aggregation Pipeline and $rand operator:
models.Payment.updateMany(
{},
[
{
$set: {
payment_settlement: {
$arrayElemAt: [
["pending", "settled"],
{ $round: { $rand: {} } }
]
}
}
}
]
)
MongoPlayground
Or if your array have more than 2 elements, you can use $multiply with $rand:
models.Payment.updateMany(
{},
[
{
$set: {
payment_settlement: {
$arrayElemAt: [
["pending", "settled", "cancelled"],
{ $round: { $multiply: [{ $rand: {} }, 2] } }
]
}
}
}
]
)
MongoPlayground

Mongoose - Query deeply nested Objects

I currently have a problem where I have to update entries in a deeply nested Document. Now to simplify my problem I have this example. Let's assume I store cars in my MongoDB. A Document would look like this
{
Make: "BMW",
Model: "3Series",
Wheels: [
{
_id: someObjectId
Size: "19 inch",
Screws: [
{
_id: someObjectId
Type : "M15x40"
},
{
_id: someObjectId
Type : "M15x40"
}
]
}
]
}
Now if I want to update a specific Wheel, my code would look somewhat like this
CarModel.findOneAndUpdate({
"_id": CarId, "Wheels._id": WheelId
}, {
"$set" : {
"Wheels.$.Size": NewSize
}
})
Now this works. But I am pretty lost on how I would update an specific screw as I am going through 2 Arrays. Any Idea how I could make this work?
You need arrayFilters functionality to define the path for more than one nested array:
CarModel.findOneAndUpdate(
{ "_id": CarId },
{ $set: { "Wheels.$[wheel].Screws.$[screw].Type": "something" } },
{ arrayFilters: [ { 'wheel._id': WheelId }, { 'screw._id': screwId } ] })

MongoDb nested Array retrieve

i am using mongodb 2.6
my schema
{
list:[
{ Sno:1,
sublist:[
{
subid:"1"
dats:"result"
},
{
subid:"2"
dats:"result"
}
]
},
{ Sno:2,
sublist:[
{
subid:"3"
dats:"result"
},
{
subid:"4"
dats:"result"
}
]
}
]
}
db.test.find({"list.sublist.subid": 2});
i want to return only matched data like this
i don't know how to use mapreduce for this solution
{
sublist:[
{
subid:"1"
dats:"result"
}
]
}
You will need to use a projection http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/
In your case try with $elemMatch (http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/#proj._S_elemMatch)
db.test.find( {},
{ sublist: { $elemMatch: { subid: "1" } } } )

Resources