MongoDB , add and format fields on array result - mongodb

I have this document:
[{
_id: "5a9eff23b9eea111a00016c8",
participants: [
2,
3
]
}]
I would like to know if it's possible to add and format fields on array result, something like this.
{
_id: "5a9eff23b9eea111a00016c8",
participants: [
{
_id: 2,
order: 22,
},
{
_id: 3,
order: 22,
}
]
}
This should not be saved in the database, it should be only attached on response.
If it's possible, I would like an advice.
#rollstuhlfahrer
Well , i don't think so , these fields ( order , _id) , doesn't exists in other table , they are custom

I've figured it out. Works well. Done in PHP.
I've used $map , see the documentation below.
https://docs.mongodb.com/manual/reference/operator/aggregation/map/
[
'$project' => [
'_id' => 0,
'title' => '$title',
'participants' => [
'$map' => [
'input' => '$participants',
'as' => 'part',
'in' => [
'recipient' => '$$part',
'status' => false,
]
]
]
]]
Here is the result:
{
title: "Channel#O4ScAPkYLz",
participants: [
{
recipient: 2,
status: false
},
{
recipient: 1,
status: false
}
]
}

Related

Replacing field while taking data from MongoDB by aggregation

community,
I struggle with replacing values while getting data from MongoDB by using aggregation.
Let’s imagine we have two collections:
mappedUsers = [
{
groupName: 'Group 1',
users: [
'Nick',
'John',
]
},
{
groupName: 'Group 2',
users: [
'Mark',
'Samuel',
]
}
]
data = [
{
date: '22/13/07',
results: [
{
user: 'Nick',
result: 5
},
{
user: 'Mark',
result: 7
}
]
},
{
date: '22/13/06',
results: [
{
user: 'John',
result: 6
},
{
user: 'Helga',
result: 9
}
]
},
]
I want to replace users with their groups. If a user doesn’t belong to any group we get his name. Same table with just mapped users:
results = [
{
date: '22/13/07',
results: [
{
user: 'Group 1', <-- replaced
result: 5
},
{
**user: 'Group 2', <-- replaced
result: 7
}
]
},
{
date: '22/13/06',
results: [
{
**user: 'Group 1', <-- replaced
result: 6
},
{
**user: 'Helga', <-- NOT replaced
result: 9
}
]
},
]
How can I replace those values?

MongoDB query - unwind and match preserving null OR different value/ add a new field based on a condition

If a have a following structure :
{
_id: 1,
name: 'a',
info: []
},
{
_id: 2,
name: 'b',
info: [
{
infoID: 100,
infoData: 'my info'
}
]
},
{
_id: 3,
name: 'c',
info: [
{
infoID: 200,
infoData: 'some info 200'
},
{
infoID: 300,
infoData: 'some info 300'
}
]
}
I need to query in such a way to obtain the documents where infoID is 100 showing the infoData, or nothing if info is empty, or contains subdocuments with infoID different from 100.
That is, I would want the following output:
{
_id: 1,
name: 'a',
infoData100: null
},
{
_id: 2,
name: 'b',
infoData100: 'my info'
},
{
_id: 3,
name: 'c',
infoData100: null
}
If I $unwind by info and $match by infoID: 100, I lose records 1 and 3.
Thanks for your responses.
Try below query :
Query :
db.collection.aggregate([
/** Adding a new field or you can use $project instead of addFields */
{
$addFields: {
infoData100: {
$cond: [
{
$in: [100, "$info.infoID"] // Check if any of objects 'info.infoID' has value 100
},
{
// If any of those has get that object & get infoData & assign it to 'infoData100' field
$let: {
vars: {
data: {
$arrayElemAt: [
{
$filter: {
input: "$info",
cond: { $eq: ["$$this.infoID", 100] }
}
},
0
]
}
},
in: "$$data.infoData"
}
},
null // If none has return NULL
]
}
}
}
]);
Test : MongoDB-Playground

Get unique array values records with one value exist

I have messenging platform in my app and I'm saving each message in the following format
{
userIds: [ 'user1Id', 'user2Id' ],
msg: "message",
sentBy: 'user1',
sentAt: new Date()
}
{
userIds: [ 'user1Id', 'user3Id' ],
msg: "message",
sentBy: 'user1',
sentAt: new Date()
}
{
userIds: [ 'user1Id', 'user2Id' ],
msg: "message",
sentBy: 'user1',
sentAt: new Date()
}
Is there any way to get unique conversations from the collection?
for example from above list I want to get
{
userIds: [ 'user1Id', 'user2Id' ],
msg: "message",
sentBy: 'user1',
sentAt: new Date()
}
{
userIds: [ 'user1Id', 'user3Id' ],
msg: "message",
sentBy: 'user1',
sentAt: new Date()
}
these two records,
What can be the mongo query here?
Is there any other way than querying all the records and do unique manually?
or anyone suggests better schema, I just started with this feature so I'm in a position to change schema.
I consider using like
{
userIds: [ 'user1Id', 'user2Id' ],
msgs: [
{
msg: "message",
sentBy: 'user1',
sentAt: new Date()
},
{
msg: "message",
sentBy: 'user2',
sentAt: new Date()
}
],
modifiedAt: new Date()
}
but decided against it because whenever there is new msg added to msgs array the whole field will be sent to client so using the first schema.
Any suggestions appreaciated. Thanks.
you can use aggregation to do that,
.aggregate([{$group:{_id:"$userIds"}}])
Refer this to more details
And you can use $project option for make the return doc as the format you wish.
I suggest you simply use an aggregation. For example:
db.test.aggregate( {$group: {_id: "$userIds" } } )
Will return
{
"result" : [
{
"_id" : [
"user1Id",
"user3Id"
]
},
{
"_id" : [
"user1Id",
"user2Id"
]
}
],
"ok" : 1
}
You will find more details in the docs Aggregation-Distinct.

is there an option to unwind only when the array isn't empty?

i'm trying to run query with unwind. (aggregation)
the problem is that when i'm running unwind on an empty array I get empty result.
I know that this is a problem:
If the array holds an empty array ([]) in an input document, the
pipeline ignores the input document and will not output documents for
that input document. (from MongoDB docs)
is there an option that i can run 'unwind' only when the array i'm trying to unwind isn't empty?
EDIT:
$match = [
'_id' => ['$in' => $ids]
];
$project = [
'name' => true,
'sum1' => true,
'array1' => true,
'array2' => true,
'array3' => true
];
$group = [
'_id' => '$name',
'sum1' => ['$sum' => '$sum1'],
'array1' => ['$push' => '$array1'],
'array2' => ['$push' => '$array2'],
'array3' => ['$push' => '$array3']
];
$query = [
['$match' => $match],
['$project' => $project],
['$group' => $group],
['$unwind' => '$array1'],
['$unwind' => '$array2'],
['$unwind' => '$array3']
];
$ret = mongo_get_db()
->selectCollection("collection")
->aggregate($query);
EDIT2:
{
name: ‘name1’
sum1: 2
array1:
[
{
id: 111
name: 222
}
]
array2: []
array3: []
}
{
name: ‘name1’
sum1: 10
array1:
[
{
id: 122
name: 333
}
]
array2: []
array3: []
}
RESULT:
{
name: ‘name1’
sum1: 12
array1:
[
{
id: 111
name: 222
}
{
id: 122
name: 333
}
]
array2: []
array3: []
}
tnx :)
You could try a $match operator prior to the $unwind that filters documents which have the array that has at least an element, using the logic that there exists at least the first element indexed 0 in the array (with the dot notation):
{ $match: { "array_field.0": { $exists: true } } };
Why not simply check if the array is empty?
if(myArray.length === 0) { /* call your code here */ }

How can i update the ids field?

Unfortunately, I cannot use positional operators since there is a bug that doesn't allow deeper than 1 embedded document: https://jira.mongodb.org/browse/SERVER-831
So this wont work (using the Mongodb Ruby driver):
stat_profile.update({ profile_id: profile.id, providers: { '$elemMatch' => { provider_name: 'foo', dates: { '$elemMatch' => { date: 20130911, relationships: { '$elemMatch' => { relationship_type: 'friend' } } } } } } },
{ '$set' => { 'providers.$.dates.$.relationships.$.ids' => [1,2,3] } })
Given the following collection. Relationships is embedded in dates, dates is embedded in providers.
How do I update the ids field?
{
"_id" => BSON::ObjectId('523048983858f61767000008'),
"profile_id" => 3,
"providers" => [
[0] {
"provider_name" => "foo",
"dates" => [
[0] {
"date" => 20130911,
"relationships" => [
[0] {
"relationship_type" => "acquaintance",
"count" => 0
},
[1] {
"relationship_type" => "friend",
"count" => 0,
"males_count" => 0,
"females_count" => 0,
"top_ten_countries" => [],
"ids" => []
}
]
}
]
}
]
}