I have a collection that looks like the ff:
{
"word":"approve",
"related" : [
{
"relationshipType" : "cross-reference",
"words" : [
"note"
]
},
{
"relationshipType" : "synonym",
"words" : [
"demonstrate",
"ratify",
]
}
],
},
{
"word": "note",
"related" : [
{
"relationshipType" : "synonym",
"words" : [
"butt",
"need",
],
},
{
"relationshipType" : "hypernym",
"words" : [
"air",
"tone",
]
},
{
"relationshipType" : "cross-reference",
"words" : [
"sign",
"letter",
"distinction",
"notice",
]
},
],
}
I want to group/categorize all the objects which have a word in another object, be it
the name (as the cross-reference field of 'approve', has note. searches for the word 'note'.
or
the word is in another object's related words. like having a synonym of 'ratify' under 'approve' then looking for other objects that have have 'ratify' in any field of their related words.
Then save these to a new collection called categories.
result should Be:
{
"category": 1,
"words":["approve","note"],
}
...and the value of the word field for all the linked objects in the words array.
Any way how to do this.. i'm thinking about some sort of recursion in checking links but i'm not sure how to implement. another potential problem is going back to the parent layer creating an infinite loop of sorts.
and is it possible through map reduce?
EDIT: clarity.
Related
I have a document structure something along the lines of the following:
{
"_id" : "777",
"someKey" : "someValue",
"someArray" : [
{
"name" : "name1",
"someNestedArray" : [
{
"name" : "value"
},
{
"name" : "delete me"
}
]
}
]
}
I want to delete the nested array element with the value "delete me".
I know I can find documents which match this description using nested $elemMatch expressions. What is the query syntax for removing the element in question?
To delete the item in question you're actually going to use an update. More specifically you're going to do an update with the $pull command which will remove the item from the array.
db.temp.update(
{ _id : "777" },
{$pull : {"someArray.0.someNestedArray" : {"name":"delete me"}}}
)
There's a little bit of "magic" happening here. Using .0 indicates that we know that we are modifying the 0th item of someArray. Using {"name":"delete me"} indicates that we know the exact data that we plan to remove.
This process works just fine if you load the data into a client and then perform the update. This process works less well if you want to do "generic" queries that perform these operations.
I think it's easiest to simply recognize that updating arrays of sub-documents generally requires that you have the original in memory at some point.
In response to the first comment below, you can probably help your situation by changing the data structure a little
"someObjects" : {
"name1": {
"someNestedArray" : [
{
"name" : "value"
},
{
"name" : "delete me"
}
]
}
}
Now you can do {$pull : { "someObjects.name1.someNestedArray" : ...
Here's the problem with your structure. MongoDB does not have very good support for manipulating "sub-arrays". Your structure has an array of objects and those objects contain arrays of more objects.
If you have the following structure, you are going to have a difficult time using things like $pull:
array [
{ subarray : array [] },
{ subarray : array [] },
]
If your structure looks like that and you want to update subarray you have two options:
Change your structure so that you can leverage $pull.
Don't use $pull. Load the entire object into a client and use findAndModify.
MongoDB 3.6 added $[] operator that facilitates updates to arrays that contain embedded documents. So the problem can be solved by:
db.test.update(
{ _id : "777" },
{$pull : {"someArray.$[].someNestedArray" : {"name":"delete me"}}}
)
As #Melkor has commented (should probably be an answer as itself),
If you do not know the index use:
{
_id: TheMainID,
"theArray._id": TheArrayID
},
{
$pull: {
"theArray.$.theNestedArray": {
_id: theNestedArrayID
}
}
}
From MongoDB 3.6 on you can use arrayFilters to do this:
db.test.update(
{ _id: "777" },
{ $pull: { "someArray.$[elem].someNestedArray": { name: "delete me" } } },
{ arrayFilters: [{ "elem.name": "name1"}] }
)
see also https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/index.html#update-all-documents-that-match-arrayfilters-in-an-array
Other example and usage could be like this:
{
"company": {
"location": {
"postalCode": "12345",
"Address": "Address1",
"city": "Frankfurt",
"state": "Hessen",
"country": "Germany"
},
"establishmentDate": "2019-04-29T14:12:37.206Z",
"companyId": "1",
"ceo": "XYZ"
},
"items": [{
"name": "itemA",
"unit": "kg",
"price": "10"
},
{
"name": "itemB",
"unit": "ltr",
"price": "20"
}
]
}
DELETE : Mongodb Query to delete ItemB:
db.getCollection('test').update(
{"company.companyId":"1","company.location.city":"Frankfurt"},
{$pull : {"items" : {"name":"itemB"}}}
)
FIND: Find query for itemB:
db.getCollection('test').find(
{"company.companyId":"1","company.location.city":"Frankfurt","items.name":"itemB"},
{ "items.$": 1 }
)
3.UPDATE : update query for itemB:
db.getCollection('test').update
(
{"company.companyId":"1","company.location.city":"Frankfurt","items.name":"itemB"},
{ $set: { "items.$[].price" : 90 }},
{ multi: true });
I need to know the best way to get following results
courseFrequency : [
{
'courses': [
'a.i'
],
'count' : 1
},
{
'courses': [
'robotics'
],
'count' : 2
},
{
'courses': [
'software engineering', 'a.i'
],
'count' : 2
},
{
'courses': [
'software engineering', 'a.i','robotics'
],
'count' : 1
}
]
from following json data.
arr = [
{
'courses': [
'a.i'
]
},
{
'courses': [
'robotics'
]
},
{
'courses': [
'software engineering', 'a.i'
]
},
{
'courses': [
'robotics'
]
},
{
'courses': [
'software engineering', 'a.i'
],
'courses': [
'software engineering', 'a.i','robotics'
]
}];
Basically i need to find out the unique courses and their frequency. What is the most optimal way to do that ?
const hash = {}, result = [];
for(const {courses} of arr){
const k = courses.join("$");
if(hash[k]){
hash[k].count++;
} else {
result.push(hash[k] = { courses, count : 1 });
}
}
Simply use a hashmap to find duplicates. As arrays are compared by reference, we need to join it to a string for referencing ( note that this will fail if a coursename contains the joining symbol ($))
There both of them are best for area relates to them.These concepts are heaving their own property and methods to accomplish a certain task like JSON used for data transfer and cross browsing aspect as the common type data value.Arrays are really good at storing ordered lists and ordering things while the cost of removing/splicing elements is a bit higher.
JSON is a representation of the data structure, it's not an object or an array.
JSON can be used to send data from the server to the browser, for example, because it is easy for JavaScript to parse into a normal JavaScript data structure.for doing an action on JSON data you need to convert it into an object which is also seamed some property like ARRAY.
Arrays are really good at storing ordered lists and ordering things while the cost of removing/splicing elements is a bit higher.
Relative link
Relative link
I have a document in my mongo instance in below format,
{
"_id" : "08d4a242-08fb-07f7-46e5-8717a81d5b70",
"fname" : "john",
"created_date" : ISODate("2017-05-24T01:13:06.829Z"),
"customProp" : [
[
"customX","{\"some data related to X \"}"
],
[
"customY","{\"some data related to Y \"}"
],
[
"customZ","{\"some data related to Z \"}"
]
]
}
the elements/values like "customX","customY" & "customZ" are not necessarily be in all documents. How to retrieve all the values in second element of "customProp" array, in this document it contains "customZ"?
I'm able to use following query to filter & find all the documents which are having "customZ" element,
db.getCollection('col1').find({$and : [{"customProp":{$elemMatch:{0:"customZ"}}}, {"created": { $gte: ISODate("2017-05-22T00:00:00.000Z") }}] },{"created":1}).limit(1) .pretty()
output:
{
"_id" : "08d4a242-08fb-07f7-46e5-8717a81d5b45",
"created" : ISODate("2017-05-24T01:13:06.829Z")
}
but finding a way to retrieve all the values in second element of array where the first value is "customZ".
expected result:
{
"_id" : "08d4a242-08fb-07f7-46e5-8717a81d5b45",
"created" : ISODate("2017-05-24T01:13:06.829Z"),
"customPro": ["customZ","{\"some data related to Z \"}"]
}
I'm fine if my query just returns
{
"{\"some data related to Z \"}"
}
Well it is a nested array, which is not a great idea but you are in fact matching the element with the $elemMatch expression, so you do get the position in the "outer" array of customProp, which allows you to project with the positional $ operator:
db.getCollection('coll1').find(
{
"customProp":{ "$elemMatch": { "0": "customZ" } },
"created_date": { "$gte": ISODate("2017-05-22T00:00:00.000Z") }
},
{ "created_date": 1, "customProp.$": 1 }
)
That yields the result:
{
"_id" : "08d4a242-08fb-07f7-46e5-8717a81d5b70",
"created_date" : ISODate("2017-05-24T01:13:06.829Z"),
"customProp" : [
[
"customZ",
"{\"some data related to Z \"}"
]
]
}
Where customProp is of course still in a nested array, but when processing the individual documents in python you can just access the property at the array index:
doc['customProp'][0][1]
Which of course returns the value:
'{"some data related to Z "}'
Same goes for JavaScript really, which is basically identical in syntax. As a shell example:
db.getCollection('coll1').find(
{
"customProp":{ "$elemMatch": { "0": "customZ" } },
"created_date": { "$gte": ISODate("2017-05-22T00:00:00.000Z") }
},
{ "created_date": 1, "customProp.$": 1 }
).map(function(doc) {
doc['customProp'] = doc['customProp'][0][1];
return doc;
})
And the output:
{
"_id" : "08d4a242-08fb-07f7-46e5-8717a81d5b70",
"created_date" : ISODate("2017-05-24T01:13:06.829Z"),
"customProp" : "{\"some data related to Z \"}"
}
And the positional $ projection here ensures there is only one element in the returned array, so the notation is always the same to extract from all document results. So you get the matched element from the database, and you extract the property through the code.
Also note that you do not need $and here since all the query arguments are already AND conditions. This is the MongoDB default, so you do not need to explicitly express it. See how much nicer this looks without it.
I'm trying to delete ($pull) an object from an array that's embedded. (Using javascript/node.js driver.)
Here is the sample data, where one, two, three are the levels:
{
one : "All",
one : [
{
name: "People",
two: [
{
three_id: 123,
three: "Jonny",
},
{
three_id: 456,
three: "Bobby",
}
]
},
{
name: "Animals",
two: [
{
three_id: 828,
three: "Cat",
},
{
three_id: 282,
three: "Dog",
}
]
}
]
}
In this example, I'm trying get rid of "Bobby".
I can successfully match the document at the "three level" if I want, like this:
db.test.find({"one.two.three_id" : 456});
However, I've no idea how to eliminate that record using update. Here are some attempts, none of which work:
// failed attempts
db.test.update({"one.two.three_id" : 456}, {$pull:{'one.$.two.$.three_id': 456}});
db.test.update({"one.two.three_id" : 456}, {$pull:{'three_id': 456}});
// deletes entire level two "People"
db.test.update({"one.two.three_id" : 456}, {$pull: {one: {two : {$elemMatch: {'three_id': 456}}}}});
I read that you cannot use two positional $ operators and that you have to know the index position for the second one. However, I want to avoid having to use the index of the embedded dictionary I want to delete.
reference:
Mongodb on pull
http://docs.mongodb.org/manual/reference/operator/update/pull/
The value of the key in your $pull object needs to be the path of the array that you're targeting. This appears to work:
db.test.update(
{'one.two.three_id': 456},
{$pull: {'one.$.two': {three_id: 456}}}
);
It looks like the $ represents the index of the first matched array level in this case so it works even though we're matching across multiple nesting levels.
Im new to JSON and I have to deal with a complex one.
Please see image below:
It has an error:
I don't know how to properly separate the 2 json arrays. I even tried to use : instead of , on line 18 but I still get errors. BTW, I use http://jsonlint.com/ to validate.
On line 2 you gave a key, but failed to do so on line 19. You have to keep the structure.
Remove the key on line 2, they shouldn't be used for arrays in that way.
Edit: In addition, you are trying to put arrays right in objects, switch the opening and ending object marks ({}) with ([]) for arrays on your first and last line.
[
[
{...},
{...},
...
{...}
],
[
{...},
{...},
...
{...}
],
...
[
{...},
{...},
...
{...}
]
]
I believe the correct way to build this JSON should be:
{
"glEntries": [
{
"generalLedgerId":1,
"accountId": 34,
"amount" : 32334.23,
"descripction": "desc1",
"debit" : "Yes"
},
{
"generalLedgerId":2,
"accountId": 35,
"amount" : 323.23,
"descripction": "desc",
"debit" : "Yes"
},
...
]
}
There are many ways to construct JSON data, but it depends on your data and the way you want to present it. Here are a couple examples - hope it helps:
{
"glEntries": [
{
"object1-prop1": "one"
},
{
"object2-prop1": 1,
"object2-prop2": "two"
},
{
"object3-prop1": [
"a",
"r",
"r",
"a",
"y"
],
"object3-prop1.1": "string"
}
],
"otherEntries": [
{
"objectx": "x"
},
{
"objecty": "y"
},
{
"objectz": [
1,
2,
3,
4
]
}
],
"oneEntry": "json"
}
Other Example:
[
{
"obj1-prop": 222
},
{
"obj2-prop": "object2"
},
{
"obj3-prop": "Object3"
},
[
"a",
"r",
"r",
"a",
"y",
777,
888
],
"string",
178,
{
"objectProp": "testing123"
}
]
You have more {} than needed and will make parsing your JSON more difficult:
Structure will work a lot better like this:
{"glentries":[
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"},
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"},
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"}
]
}
Now glentries is an array of objects that have multiple properties to them.
alert( glentries[0].property2 )
The parent structure is an Object, so it is expecting a string Key for the second array. It it's supposed to be an array of arrays, you should be using an array and not an Object.