Having trouble in nested array of abjects - javascript

I've used Mongodb aggregation, $facet as I wanted to count every value of "reli" and "prov" from the collection.
This is my code to get results from db.
const keyy = await db.aggregate([
$facet: { "reli": [
{ $group: { _id: '$reli', count: { $sum: 1 } } } ],
"prov": [
{ $group: { _id: '$prov', count: { $sum: 1 } } }
],
])
Output Looks like this:
[
{
"reli": [
{
"_id": "abcdef",
"count": 6
},
{
"_id": "ghij",
"count": 1
},
],
"prov": [
{
"_id": "hello",
"count": 63
},
{
"_id": "hey",
"count": 9
},
]
}
]
But I want That my Expected output is :
[
{
"reli":[
{abcdef: 6},
{ghij: 1}
],
"prov":[
{"hello": 63},
{"hey": 9}
]
}
]

You can iterate using $map and generate the new array with the values you want using $arrayToObject like this:
This query simply overwrite values reli and prov with the result of the map. That result is an array compound by objects where the key k is the _id value and the value v is the count value.
db.collection.aggregate([
{
"$project": {
"reli": {
"$map": {
"input": "$reli",
"in": {
"$arrayToObject": [
[
{
k: "$$this._id",
v: "$$this.count"
}
]
]
}
}
},
"prov": {
"$map": {
"input": "$prov",
"in": {
"$arrayToObject": [
[
{
k: "$$this._id",
v: "$$this.count"
}
]
]
}
}
}
}
}
])
Example here

Related

Mongo Project by referencing external Dictionary

I have a collection in MongoDB:
[
{
"uid": "a1"
},
{
"uid": "a2"
}
]
and a dictionary in my JS code
let dict = { "a1": "ref1", "a1": "ref2" };
I want to do an aggregate that will somehow join the two.
let k = ;
this.model.aggregate([
{
$match: {
uid: { $in: Object.keys(dict) }
}
},
{
$project: {
ref: // here is where I want to add the equivalent reference
}
}
])
The expected output would be something like this:
[{uid: "a1", ref: "ref1"}, {uid: "a2", ref: "ref2}]
Is there a way to get the reference from the dict into the $project?
I don't know if there is an easier way to do it, but here's how I achieved it:
db.collection.aggregate([
{
$match: {
uid: {
$in: [
"a1",
"a2"
]
}
}
},
{
"$project": {
"array": {
"$objectToArray": {
"a1": "ref1",
"a2": "ref2"
}
},
"uid": 1,
}
},
{
"$project": {
"ref": {
"$filter": {
"input": "$array",
"as": "elem",
"cond": {
"$eq": [
"$$elem.k",
"$uid"
]
}
}
},
uid: 1,
},
},
{
"$project": {
ref: {
"$arrayElemAt": [
"$ref.v",
0
]
},
uid: 1,
}
}
])
See it working here. I hope you get the idea and convert it into the nodejs equivalent version.

MongoDB: append as field the matched element from array

I have the following code:
const array = ['a', 'b', 'c']
await collection.aggregate([
{
$match: {
codes: { $in: array }
}
},
{
$addFields: { matchedField: "codes.$" } // <--- does not work
},
]).toArray();
I need to append the matched element from within array to the returned results. Is it possible to do that?
My collection contains documents with the following scheme:
{
"color": "red",
"codes": [ "b" ]
}
I need the aggregation directive to return this:
{
"color": "red",
"codes": [ "b" ],
"matchedField": "b",
}
$filter
db.collection.aggregate([
{
"$match": {
"codes": {
"$in": [
"a",
"b",
"c"
]
}
}
},
{
"$set": {
codes: {
$filter: {
input: "$codes",
as: "c",
cond: {
$in: [
"$$c",
[
"a",
"b",
"c"
]
]
}
}
}
}
}
])
mongoplayground
$setIntersection
db.collection.aggregate([
{
"$match": {
"codes": {
"$in": [
"a",
"b",
"c"
]
}
}
},
{
"$set": {
codes: {
$setIntersection: [
"$codes",
[
"a",
"b",
"c"
]
]
}
}
}
])
mongoplayground

How to change field from subdocument a parent field in Mongoose

I am trying to export Mongo data to XLSX which requires all the data to be in the parent map but currently I have data in this format:
[
{
"_id": "eatete",
"competition": {
"_id": "eatete"
"name": "Some competition name"
},
"members": [
{
"_id": "eatete",
"name": "Saad"
},
{
"_id": "eatete",
"name": "Saad2"
}
],
"leader": {
"name": "Saad",
"institute": {
"_id": "eatete",
"name": "Some institute name"
}
},
}
]
Ideally, the data should be:
[
{
"_id": "eatete",
"competition": "Some competition name"
"member0name": "Saad",
"member1name": "Saad2",
"leadername": "Saad",
"institute": "Some institute name"
}
]
So basically what I want is to refer the data of fields of subdocuments as if those were part of parent document, like competitions = competitions.name.
Can you please help me how can I do so using Mongoose.
Thanks
With some more aggregation trick
db.collection.aggregate([
{ "$unwind": { "path": "$members", "includeArrayIndex": "i" }},
{ "$group": {
"_id": "$_id",
"competition": { "$first": "$competition.name" },
"leadername": { "$first": "$leader.name" },
"institute": { "$first": "$leader.institute.name" },
"data": {
"$push": {
"k": { "$concat": ["members", { "$toLower": "$i" }, "name"] },
"v": "$members.name"
}
}
}},
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": ["$$ROOT", { "$arrayToObject": "$data" }]
}
}},
{ "$project": { "data": 0 }}
])
You can try below aggregation on your Model:
let resultt = await Model.aggregate([
{
$project: {
_id: 1,
competition: "$competition.name",
leadername: "$leader.name",
institute: "$leader.institute.name",
members: {
$map: {
input: { $range: [ 0, { $size: "$members" } ] },
in: {
k: { $concat: [ "member", { $toString: "$$this" }, "name" ] },
v: {
$let: {
vars: { current: { $arrayElemAt: [ "$members", "$$this" ] } },
in: "$$current.name"
}
}
}
}
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [ "$$ROOT", { $arrayToObject: "$members" } ]
}
}
},
{
$project: {
members: 0
}
}
])
Since you need to dynamically evaluate your keys based on indexes you can use $map with $range to map a list of indexes into keys of a new object. Then you can use $arrayToObject to get an object from those keys and $mergeObjects with $replaceRoot to flatten this object structure.

Getting only last field in mongoose $in Operator

I am trying to find all person records that time between start and end and have place id in [1,2] This is my query:
Person.find({
time: {
$gte: start,
$lt: end
},
"place.place_id": { $in: [1,2] }
}, {
"time":1,
"place.$": 1
},
function (err, docs) {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send(docs);
}
}
);
But I am getting only one place. This is my output
[
{
"_id": "5bffc1e9bd35e42020c05cf1",
"time": "2018-11-29T10:38:01.401Z",
"places": [
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 1,
"place_name": "test1"
}
]
},
{
"_id": "5bffc256bd35e42020c05de4",
"time": "2018-11-29T10:40:01.324Z",
"places": [
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 1,
"place_name": "test1",
}
]
}
]
I am getting only place which have id 1 my desired output is
[
{
"_id": "5bffc1e9bd35e42020c05cf1",
"time": "2018-11-29T10:38:01.401Z",
"places": [
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 1,
"place_name": "test1"
},
{
"_id": "5bffc1e9bd35e42020c05de3",
"place_id": 2,
"place_name": "test2"
}
]
},
{
"_id": "5bffc256bd35e42020c05de4",
"time": "2018-11-29T10:40:01.324Z",
"places": [
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 1,
"place_name": "test1",
},
{
"_id": "5bffc256bd35e42020c05ed6",
"place_id": 2,
"place_name": "test2",
}
]
}
]
Update
Tried this but this gives me empty object
Persons.find({
time: {
$gte: start,
$lt: end
},
places: {
$filter: {
input: "$places",
as: "place",
cond: { $in: ["$$place.place_id",[ 1,2 ]] }
}
}
},
function (err, docs) {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send(docs);
}
}
);
};
What am I doing wrong?? I also tried $elemMatch, $all Operator but same output.
How can I get all these places?
Thanks.
Update2
I am entrying data after every 2 minutes this is start and end values
var end = new Date();
var start = new Date(end);
start.setMinutes(end.getMinutes() - 10);
You need to use aggregation for this. Something like
db.collection.aggregate([
{ "$match": {
"time": { "$gte": start, "$lt": end },
"place.place_id": { "$in": [1, 2] }
}},
{ "$project": {
"time": 1,
"places": {
"$filter": {
"input": "$places",
"as": "place",
"cond": { "$in": ["$$place.place_id", [1, 2]] }
}
}
}}
])

Why the following query does not return any data?

I have a collection in mongodb and indexed on the field name , i do a free search using the following query to get matched results and limit to 5,
db.getCollection('_event').aggregate([
{
"$match": {
"$and": [
{
"$text": {
"$search": "liver"
}
},
{},
{}
]
}
},
{
"$group": {
"_id": null,
"count": {
"$sum": 1
},
"results": {
"$push": "$$ROOT"
}
}
},
{
"$project": {
"count": 1,
"results": {
"$slice": [
"$results",
5
]
}
}
}
])
but there is a data with liverpool . when i do replace it with "$search": "liverpool" it returns data.
what is the issue here?

Categories

Resources