Assume I have a collection with documents that look like this:
{
"_id": ";lkajsdflhkadfhaewifjasdkfjalksdfjs",
"tree": [
{ "id": "a", "name": "One" },
{ "id": "b", "name": "Two" },
{ "id": "c", "name": "Three" },
{ "id": "d", "name": "Four" }
]
}
Now let's say I want to replace the a, b, and c entries in my tree array with e, f, and c entries. Is it possible to do that replace with an update query? If not, is there a way to select the document such that the tree array only contains the c and d entries (or just the d entry)? I want my document to look like this:
{
"_id": ";lkajsdflhkadfhaewifjasdkfjalksdfjs",
"tree": [
{ "id": "e", "name": "Five" },
{ "id": "f", "name": "Six" },
{ "id": "c", "name": "Three" },
{ "id": "d", "name": "Four" }
]
}
Order of the tree array matters. I'm aware of $splice, but I do not know ahead of time the index of the c entry. Also, the index may vary between documents. Can I do a query inside of $splice that lets me find the index?
How about doing a find().forEach?
db.test.find().forEach(function(doc){for (var i = 0; i < doc.tree.length; i++){
switch(doc.tree[i].id){
case "a": doc.tree[i] = { "id": "e", "name": "Five" };
break;
case "b": doc.tree[i] = { "id": "f", "name": "Six" };
break;
}} db.test.save(doc)});
Of course you can put in more specific logic to fit your rules but this will simply replace the a entries with e and b with f.
Related
Sample Doc :
{
"id": "K",
"powers": [
{
"label": "a",
"Rating": 7
},
{
"label": "b",
"Rating": 3
},
{
"label": "c",
"Rating": 4
},
{
"label": "d",
"Rating": 5
}
],
"phy": {
"height": 67,
"weight": 150
}
}
For this collection, I want to count how many distinct powers each id has.
I want the result as - ID =K, distinct power label - 4
So the easiest way to get it done is
/** db.collection.distinct('field on which distinct is needed', condition) */
db.collection.distinct('powers.label', {"id" : "K"})
As it will be an array, You can do .length in code to get the unique length.
Ref : .distinct()
I have PostgreSQL 9.5 table(instrument) having 2 columns instrument_id and user_maps as shown below:
I want to fetch all instruments based on following conditions:
Loop through each json object in user_maps
count the number of json objects having status in Y, N or D
Count should be more than 2.
Note: user_maps is an array of json object having 2 fields status and userId
Sample user_maps linked to instrument_id "I01":
[
{
"status": "Y",
"userId": "ZU201707120539150007"
},
{
"status": "D",
"userId": "ZU201707120540510008"
},
{
"status": "I",
"userId": "ZU201707120542540009"
},
{
"status": "I",
"userId": "ZU201707011725050001"
},
{
"status": "Y",
"userId": "ZU201707120552050013"
}
]
Instrument id "I01" should come in final result .
Another, Sample user_maps linked to instrument_id "I02":
[
{
"status": "I",
"userId": "ZU201707120539150007"
},
{
"status": "I",
"userId": "ZU201707120540510008"
},
{
"status": "I",
"userId": "ZU201707120542540009"
},
{
"status": "I",
"userId": "ZU201707011725050001"
},
{
"status": "Y",
"userId": "ZU201707120552050013"
}
]
Instrument id "I02" should not come in final result beacuse it has only one json having status in (Y, N,D).
If I understood correctly your request then this is how you can do it:
-- This is just test dataset as you provided
WITH test( instrument_id, user_maps ) AS (
VALUES
( 'I01'::text,
$$[
{ "status": "Y", "userId": "ZU201707120539150007" },
{ "status": "D", "userId": "ZU201707120540510008" },
{ "status": "I", "userId": "ZU201707120542540009" },
{ "status": "I", "userId": "ZU201707011725050001" },
{ "status": "Y", "userId": "ZU201707120552050013" }
]$$::jsonb ),
( 'I02'::text,
$$[
{ "status": "I", "userId": "ZU201707120539150007" },
{ "status": "I", "userId": "ZU201707120540510008" },
{ "status": "I", "userId": "ZU201707120542540009" },
{ "status": "I", "userId": "ZU201707011725050001" },
{ "status": "Y", "userId": "ZU201707120552050013" }
]$$::jsonb )
)
SELECT t.instrument_id,
count( u )
FROM test t,
jsonb_array_elements( user_maps ) u -- does lateral join to get json array elements
WHERE u -> 'status' ?| ARRAY['Y', 'N', 'D'] -- your search condition
GROUP BY 1
HAVING count( u ) > 2; -- the count condition you wanted
-- This is the result of the query
instrument_id | count
---------------+-------
I01 | 3
(1 row)
With the following JSON I want to get the max value of the email ID.
[
{
"id": 1,
"firstName": "Bill",
"lastName": "Smith",
"emails": [
{
"id": 1,
"email": "jack#jackkkfgfkfgkkkkkk.com",
"dateCreated": "2017-05-14T14:04:12.3299297-07:00"
},
{
"id": 2,
"email": "jack#jackkkfkkkkkk.com",
"dateCreated": "2017-05-14T14:04:24.1534621-07:00"
},
{
"id": 3,
"email": "jack#jackfkkkkkk.com",
"dateCreated": "2017-05-14T14:04:29.8526171-07:00"
}
]
},
{
"id": 2,
"firstName": "Bill",
"lastName": "Smith",
"emails": [
{
"id": 4,
"email": "jack#jkkkkk.com",
"dateCreated": "2017-05-14T14:04:45.8674213-07:00"
}
]
}
]
My code so far
var maxId = People.Select(p => p.Emails.Max(i => i.Id)).FirstOrDefault();
This however always returns 4, because it only check the first element. Is there a way to check all in a single linq statement? So the next value would be 5.
You want the Max Id of all the emails.
var maxId = People.SelectMany(p => p.Emails).Max(e => e.Id);
var nextId = maxId++;
Use SelectMany to flatten all the emails into one sequence and then get the Max Id from that list.
I need to produce a report on a set of documents with timestamps between two dates. The report needs to list each document, but it also needs to include a field for each document to indicate whether it's the first document in its group, which is indicated by an attribute.
There's a slight complication in the fact that although only documents between the two dates should be included, documents before the start date need to be considered when deciding if each document is the first it its set.
E.g. given the data
{ "_id": 1, "group": "A", "timestamp": "2015-01-01" }
{ "_id": 2, "group": "B", "timestamp": "2015-01-02" }
{ "_id": 3, "group": "A", "timestamp": "2015-01-03" }
{ "_id": 4, "group": "C", "timestamp": "2015-01-04" }
{ "_id": 5, "group": "B", "timestamp": "2015-01-05" }
{ "_id": 6, "group": "C", "timestamp": "2015-01-06" }
Generating a report from 2015-01-02 to 2015-01-05 would return
{ "_id": 2, "group": "B", "timestamp": "2015-01-02", "first": 1 }
{ "_id": 3, "group": "A", "timestamp": "2015-01-03", "first": 0 }
{ "_id": 4, "group": "C", "timestamp": "2015-01-04", "first": 1 }
{ "_id": 5, "group": "B", "timestamp": "2015-01-05", "first": 0 }
Currently I'm doing this by sorting all documents by group then timestamp, then looping over the entire dataset keeping track of the previous row to decide if a row inside the date range is the first of its type. With a large dataset this is very slow - it feels as though there must be a better way involving grouping or something clever but my Mongo skills aren't up to the job - any suggestions?
I have a mongo DB with several collections that contain JSON document formats shown below:
{
"questions": [
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q1",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o1"
},
{
"type": 1,
"value": "o1"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes"
]
}
},
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q2",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o2"
},
{
"type": 1,
"value": "o2"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes",
"Glenn Rhee"
]
}
}
]
}
I'm able to search for questions.questionEntry.questionItem.theQuestion for a matching criteria with:
db.questions.find({"questions.questionEntry.questionItem.theQuestion" : "q1"},{'questions.$':1}).pretty()
This works well for the questions collection but how would I do the same search across multiple collections?
Many thanks
To use the same query across multiple collections you may have to use the JavaScript bracket notation to access the collections in a loop. For example, the following queries the records database for all the collections (using the db.getCollectionNames() command) with the specified query:
use records
var colls = db.getCollectionNames(), // get all the collections in records db
query = {"questions.questionEntry.questionItem.theQuestion" : "q1"},
projection = {"questions.$": 1};
colls.forEach(function (collection){
var docs = db[collection].find(query, projection).toArray(); // use the bracket notation
docs.forEach(function (doc){ printjson(doc); });
})
You will have to do this by yourself. There is no out-of-the-box support.
You can query MongoDB multi-threaded (depending on your programming language) and aggregate the results to a unified result.