Select array inner element - mongodb

I have a trouble with mongodb data below.
I want to get data [projects][log][subject].
so, I tried like this
$project':{_id:0, projects.log.subject:1}
but it is not correct syntax..
{
"_id": ObjectID("569f3a3e9d2540764d8bde59"),
"A": "book",
"server": "us",
"projects": [
{
"domainArray": [
{
~~~~
}
],
"log": [
{
~~~~~,
"subject": "I WANT THIS"
}
],
"before": "234234234"
},
{
"domainArray": [
{
~~~~
}
],
"log": [
{
~~~~~,
"subject": "I WANT THIS"
}
],
"before": "234234234"
},....
] //end of projects
}//end of document
How can I get data group by [subject]? I have no idea about this..
Edited-
I expected data like this
{
"subject":"first",
"subject":"second",
"subject":"third",
"subject":"~~~"
}
Is it possible? I just want to get array of subject.

Not sure whether it is your expected result or not. Can you please try this:
db.project.aggregate([
{$project:{projects:1,_id:0}},
{$unwind:"$projects"},
{$unwind:"$projects.log"},
{$project:{subject:"$projects.log.subject",_id:0}}
])
and Map-Reduce for above result of word count is as below:
//map function
var map = function() {
for(var i in this.projects)
{
for(var j in this.projects[i].log)
{
var arrayWords = this.projects[i].log[j].subject.split(" ");
for(var k = 0; k < arrayWords.length; k++)
{
emit(arrayWords[k],{occurance:1});
}
}
}
};
//reduce function
function reduce(word, arrayOccurance) {
var totalOccurance = 0;
for (var i = 0; i < arrayOccurance.length; i++)
{
totalOccurance = totalOccurance + arrayOccurance[i].occurance;
}
return { occurance:totalOccurance };
}
//combine both function into operation and output result into wordOccurance collection
db.project.mapReduce(
map,
reduce,
{
query: {"projects.log.subject":"~~~~~"},
out: "wordOccurance"
}
)
//query the result output
db.wordOccurance.find()
You can change the query under mapreduce to match your subject that want to word count. Please let me know if my mapreduce function doesn't meet your expected result.
You can also refer below two pages to create and troubleshoot map and reduce function:
Troubleshoot the Map Function
Troubleshoot the Reduce Function

Related

spring-data-mongodb GroupOperation question

i have data in mongodb,just like
{
"name":"test1",
"receivedDate":"2021-05-18 00:00:52",
}
{
"name":"test2",
"receivedDate":"2021-05-18 00:00:52",
}
{
"name":"test3",
"receivedDate":"2021-05-18 00:00:52",
}
{
"name":"test4",
"receivedDate":"2021-05-18 00:00:52",
}
I want to find data with format like:
{
"name":["test1","test2","test3","test4"],
}
When I use the following code, it can run
GroupOperation group = Aggregation.group().push("name").as("name");
And result like
[
{
"_id": null,
"name": [
"test1",
"test2",
"test3",
"test4",
"test4"
]
}
]
But when I use another code
GroupOperation group = Aggregation.group();
for (int i = 0; i < params.length; i++) {
group.push(params[i]).as(params[i]);
}
it get bad result
[
{
"_id": null
}
]
what should i do?
Thanks for your suggestion
MongoDB $group operator does not allow filtering (only accumulator operators).
Your second code is trying do something like this:
{
$group:{
_id:null,
test1:{
$push:"$test1"
},
test2:{
$push:"$test2"
},
...
}
}
and you get the wrong result
Solution: Filter before grouping (MongoPlayground)
MatchOperation match = Aggregation.match(Criteria.where("name").in(Arrays.asList(params)))
GroupOperation group = Aggregation.group().push("name").as("name");
I should use this code
group = group.push(params[i]).as(params[i]);

Search Bar Filter (Nested Array)

How to use a search bar Filter for nested array objects in ionic 4 search bar
ionic version-4.7.1 below I have attached my Filter function but I couldn't use this function to filter objects inside a nested array
this.filterData = this.allData.filter(data => {if (data.letter && this.searchTerm) {
for (var i = 0; i < data.child_contacts.length; i++) {
if (
data.child_contacts[i].full_name
.toLowerCase()
.indexOf(this.searchTerm.toLowerCase()) > -1
) {
return (
data.child_contacts[i].full_name
.toLowerCase()
.indexOf(this.searchTerm.toLowerCase()) > -1
);
}
}
return false;}});
here is data that needed to be filtered
this.allData=[ {
"letter":"A",
"child_contact":[
{"full_name":"First"},
{"full_name":"second"},
{"full_name":"third"}
]
},
{
"letter":"B",
"child_contact":[
{"full_name":"First second"},
{"full_name":"Third"}
]
},
{
"letter":"C",
"child_contact":[
{"full_name":"Third"}
]
} ]
if I search 'First' my expected output would be,
[ {
"letter":"A",
"child_contact":[
{
"full_name":"First"
},
]
},
{
"letter":"B",
"child_contact":[
{
"full_name":"First"
},
]
}]
I'm not sure if this is the complete solution but one problem I can see is you are using child_contacts with an s in the filter,
for (var i = 0; i < data.child_contacts.length; i++) {
but the data is child_contact:
this.allData=[ {
"letter":"A",
"child_contact":[
{"full_name":"First"},
{"full_name":"second"},
{"full_name":"third"}
]
},

Mongo - Count up size of different named nodes (not their values but # of nodes)

In the json below I would like to find out the counts of all unique / distinct entries under several different nodes.
I think there should be a non-aggregation framework solution but i cant find either aggregation or non-aggregation.
For each node by itself I can count it using:
db.collection.distinct('nodaA.title').length
And replace the ' ' with the appropriate field for other nodes. But I want to get the counts of 'NodeB.subNoda1.author' and 'NodeB.subNode2.song' and 'NodeB.subNode3.picture' all with 1 query.
I want to get a result something like
title: 1
author: 2
song: 3
picture: 1
"nodaA": [
{
"title": "light",
"id" : 1
}
],
"NodeB": {
"subBnode1": [
{
"author": "Gazundheit"
},
{
"author": "Max Weasley"
}
],
"subBnode2": [
{
"song" : "what is love"
},
{
"song" : "gangster's paradise"
},
{
"song" : "wind is gone"
}
],
"subBnode3": [
{
"picture" : "inappropriate"
}
]
}
}
As NeilLunn pointed out it this can only be done with MapReduce, this is what i ended up with:
map:
function () {
emit("titles", this.title);
for (var key in this.nodeB) {
emit(key, this.nodeB[key]);
}
}
reduce:
function (key, values) {
var reducedValue = array.length;
return reducedValue;
|
Apologies if this doesnt exactly compile - i modified it from my actual data, but that's the gist of what i did, in case it helps anyone. If more details needed, will add.

MongoDB: query within document

I have my mongodb document like this...
{
"semantics" : [
{
"text": "abc gave payment to xyz",
"action": "gave"
},
{
"text": "abc wanted quicker solution",
"action": "want"
}
],
"keyword" : [
{
"word":"payment",
"imp":0.91
},
{
"word":"solution",
"imp":0.7
}
]
}
The requirement is to find action values for those words whose importance is more than 0.9.
In the above case, payment has importance more than 0.9 and, hence, should be considered. payment exists in one of the array and the action value in it is gave.
I am requesting help in constructing mongodb query for the same.
You can first use mapReduce:
db.collection.mapReduce(
function() {
for (var i = 0; i < this.keyword.length; i++) {
if (this.keyword[i].imp >= 0.9) {
emit(this.keyword[i].word, this.semantics)
}
}
},
function(key, values) { },
{
out: {merge: 'result'},
finalize: function(key, semantics) {
var result;
for (var i = 0; i < semantics.length; i++) {
if (semantics[i].text.indexOf(key) != -1) {
result = {key: semantics[i].action};
}
}
return result;
}
)
We don't care about the reduce function here since map will return {word with imp >= 0.9: the whole semantics}.
Later, before storing the result into result collection, finialize function is called and it goes through all semantics associated with a word and fetches all actions related to texts that contain the key word.
After this, you can db.result.find() to see the result, you will see some null result because not all key has a matched text and action, you need to clean up a bit.

mongodb - Finding the Sum of a field (if it exists) in a collection

I have the following mongodb structure
{
"_id": ObjectId("507c80a143188f9610000003"),
"date": ISODate("2012-10-15T21: 31: 13.0Z"),
"uid": NumberInt(35920),
"comp": NumberInt(770),
"fields": {
"rating": {
"parent": "rating",
"weight": NumberInt(2),
"rel_weight": 0.11,
},
"capacity": {
"parent": "capacity",
"weight": NumberInt(4),
"rel_weight": 0.89,
},
}
}
The "fields" attribute has 2 fields "rating" and "capacity" in it. But, each entry might have a different set of fields. eg. dimension, price etc.
I would like to find all entries that have "rating" under "fields" and get a sum of "weight" attribute of all such entries.
I am a newbie to mongodb and I tried using the mapReduce function, but with no avail.
Given below is the code I used. Kindly let me know where I went wrong or if there is a better solution instead of this code.
function map(){
emit(this._id,{weight:this.fields.rating.weight});
}
function reduce(key,value){
var sum = 0;
for ( var i=0; i<value.length; i++ ) {
sum += value[i].amount;
}
return sum;
}
res = db.collection_name.mapReduce(map, reduce, { query: {"fields.rating" : { $exists: true } });
I was finally able to figure it out and get it working. I have shared my code below.
var map = function(){
if(this.fields.rating){
emit(this.fields.rating.parent,this.fields.rating.weight);
}
}
var reduce = function (k, vals) {
var sum = 0;
var count = 0;
for (var i in vals) {
sum += vals[i];
count++;
}
var avg = (sum/count);
return avg;
}
var res = db.myCollection.mapReduce(map, reduce, {out:"myoutput"});