How to filter an array in an object in the SQL query - entity-framework

Assume the following classes:
class ParentObject {
guid Id {get;set;}
string SomeProp {get;set;}
List<OtherObject> OtherObjects {get;set;}
}
class OtherObject {
string PropA {get;set;}
string PropB {get;set;}
}
I want to retrieve a collection that returns all objects ParentObj which have a at least 1 object OtherObj with PropA equal to the given search parameter.
myQueryable = myQueryable.Where(mq => mq.OtherObjects.Any(oo => oo.PropA.Equals(filterParams.PropA)));
Result:
{
"parentObjects": [
{
"id": "someguid",
"someProp": "someValue",
"otherObjects": [
{
"propA": "abc",
"propB": "aaa"
},
{
"propA": "def",
"propB": "bbb"
}
]
},
{
"id": "someguid",
"someProp": "someValue",
"otherObjects": [
{
"propA": "abc",
"propB": "bbb"
},
{
"propA": "def",
"propB": "bbb"
}
]
}
]
}
My question is, how do I extend the query so OtherObjects in the result only contains those which have PropA equal to the search parameter?
So if in my example teh search parameter would be "abc" I would like this result:
{
"parentObjects": [
{
"id": "someguid",
"someProp": "someValue",
"otherObjects": [
{
"propA": "abc",
"propB": "aaa"
}
]
},
{
"id": "someguid",
"someProp": "someValue",
"otherObjects": [
{
"propA": "abc",
"propB": "bbb"
}
]
}
]
}
Fetching the data like in my first example and then filtering locally is no problem:
result.ForEach(r => r.OtherObjects = r.OtherObjects.Where(oo => oo.PropA.Equals(filterparams.PropA)).ToList());
But I would rather like to extend my LINQ query so the data which I don't need isn't fetched from the db. Assume a very large number of fields in the parentObject and otherObject so a Select to a new OtherObject is something I would really like to avoid.

Related

Sanity.io GROQ query for array of objects

I'm learning to code and now I am on the stage of a small pet project with Sanity as a CMS.
Long story short, making an API I'm trying to fetch cocktails data with votes for the cocktails. The votes are stored within persons who voted:
GROQ query
*[
_type == "cocktail" &&
!(_id in path('drafts.**'))
] {
name,
_id,
"votes" : *[_type == "person" && references(^._id)] {
votes[] {
score,
"id": cocktail._ref
}
}
}
which returns
[
{
"_id": "pdUGiuRzgLGpnc4cfx76nA",
"name": "Cuba Libre",
"votes": [
{
"votes": {
"id": "pdUGiuRzgLGpnc4cfx76nA",
"score": 2
}
},
{
"votes": {
"id": "pdUGiuRzgLGpnc4cfx76nA",
"score": 2
}
}
]
},
{
"_id": "pdUGiuRzgLGpnc4cfxBOyM",
"name": "The ERSH7",
"votes": []
}
]
As you can see, the merge provides embedded arrays of votes meanwhile I want sth like:
[{
...cocktail attributes...
"votes" : [
{score: 2, id: pdUGiuRzgLGpnc4cfx76nA},
{score: 2, id: pdUGiuRzgLGpnc4cfx76nA}
]
}
... more cocktails....
]
Trying to get this I modified the query:
*[
_type == "cocktail" &&
!(_id in path('drafts.**'))
] {
name,
_id,
"votes" : *[_type == "person" && references(^._id)].votes[] {
score,
"id": cocktail._ref
}
}
which should take a projection from every element of the votes arr. Unfortunately I get empty arrays:
[
{
"_id": "pdUGiuRzgLGpnc4cfx76nA",
"name": "Cuba Libre",
"votes": [
{},
{}
]
}
...more cocktails
]
How can I achieve the desired result?
Thank you for reading! Would appreciate any help!
Yes, had similar struggles with "flattening" the projections my self. I solved it with dot-syntax. Try just adding .votes on your first attempt:
*[
_type == "cocktail" &&
!(_id in path('drafts.**'))
]
{
name,
_id,
"votes" : *[_type == "person" && references(^._id)] {
votes[] {
score,
"id": cocktail._ref
}
}
.votes
}
If this is correct, the whole query can be simplified but I'm not at the level, yet, where I can do that without testing against a similar set ,'-)
Actually, GROQ has syntax to flatten array starting from v2021-03-25
find this example:
{
'nestedArray': [
{'foo': [1,2,3,4,5]},
{'foo': [6,7,8,9,10,11,12]},
{'foo': [13,14,15]},
]
}{
'stillNestedArray': #.nestedArray[].foo,
'flatArray': #.nestedArray[].foo[]
}
Note the [] right after foo - this is what's flatten it
So the original query from the question should look like
*[
_type == "cocktail" &&
!(_id in path('drafts.**'))
] {
name,
_id,
"votes" : *[_type == "person" && references(^._id)] {
votes[] {
score,
"id": cocktail._ref
}
}.votes[]
}

Mongodb - How to use $inc if the element is not in database

So I have a weird issue where it actually worked before but not I do just get:
pymongo.errors.WriteError: Cannot create field 'test' in element {raffleItem: []}
So before I explain the code more, my code looks like:
#email_raffleItem.raffleItem -> "TEST"
#email_raffleItem.email -> "hello#gmail.com"
if db.license.find_one({'email': email_raffleItem.email}):
db.license.update_one({
'email': email_raffleItem.email
},
{'$inc': {
'raffleItem.{}.entries'.format(email_raffleItem.raffleItem): 1
}
}, upsert=False
)
return db.license.find_one({'email': email_raffleItem.email}).get('raffleItem').get(
email_raffleItem.raffleItem).get('entries')
And the database is as simple as:
{
"email": "hello#gmail.com",
},
"raffleItem": []
}
So what it supposed to do is that whatever I write in #email_raffleItem.raffleItem etc the word TEST - it should automatic add into the database -> raffleItem a value of TEST which will add also a new element called entries and it will have a value 1. So a database should look like:
{
"email": "hello#gmail.com",
},
"raffleItem": [
{
"TEST": [ { "entries": "1"} ]
}
]
}
I think something like that I would say
However it worked before but now whenever I run my code it only returns the error. What am I doing wrong?
Update:
Currently how it looks from srinivasy's bulk_update::
How I want it to look:
From this error :
pymongo.errors.WriteError: Cannot create field 'test' in element {raffleItem: []} , it's because you're trying to do $inc on an array field that too by passing an object, additionally when you do increment on {"entries": "1"} value of entries should be a number but not a string. In your case since you've only one object in raffleItem & also in TEST you could try below query to make things work for either a push or an increment :
db.yourCollectionName.bulkWrite([
{
updateOne:
{
"filter": { "email": "hello#gmail.com", 'raffleItem.TEST.entries': { $exists: true } },
"update": { $inc: { "raffleItem.$.TEST.$[].entries": 1 } }
}
},
{
updateOne:
{
"filter": { "email": "hello#gmail.com", 'raffleItem.TEST.entries': {$exists : false} },
"update": {
$set: {
"raffleItem": [
{
"TEST": [
{
"entries": 1
}
]
}
]
}
}
}
}
])
In the query you need to replace TEST with your input variables, If you trigger TEST1 & TEST2 once while TEST thrice, then :
Output :
{
"_id" : ObjectId("5e0a3509400289966e5f8014"),
"email" : "hello#gmail.com",
"raffleItem" : [
{
"TEST2" : [
{
"entries" : 1.0
}
]
},
{
"TEST1" : [
{
"entries" : 1.0
}
]
},
{
"TEST" : [
{
"entries" : 3.0
}
]
}
]
}
Ref : .bulkwrite()
For python ref : PyMongo-bulkwrite
Pymongo version of srinivasy's bulk_update:
import pymongo
from pymongo import UpdateOne
db = pymongo.MongoClient()['mydatabase']
db.yourCollectionName.bulk_write([
UpdateOne(
{"email": "hello#gmail.com", 'raffleItem.TEST.entries': {"$exists": True}},
{"$inc": {"raffleItem.0.TEST.0.entries": 1}}
),
UpdateOne(
{"email": "hello#gmail.com", "raffleItem": []},
{"$set": {
"raffleItem": [
{
"TEST": [
{
"entries": 1
}
]
}
]
}
})
])

How to create field from substring of another field in MongoDb?

I need to create a new field from a substring (two characters string) of another field in MongoDB.
Help me, please.
Example:
field1 field2
abcdef ab
qwerty qw
opuytj op
My code:
db.mycollection.update({}, {$set : {"field2": { $substr: [ {"field1"}, 0, 2 ] } }},
{upsert:false, multi:true})
if you have mongodb server v4.2 or newer you can do it easily like so:
db.mycollection.updateMany({}, [
{
"$set": {
"field2": {
"$substr": ["$field1", 0, 2]
}
}
}
])
the above was generated using the following c# code:
using MongoDB.Entities;
using MongoDB.Entities.Core;
namespace StackOverflow
{
public class Item : Entity
{
public string field1 { get; set; }
}
public class Program
{
private static void Main()
{
new DB("test", "localhost");
(new[] {
new Item {field1 = "abcdef"},
new Item {field1 = "qwerty"},
new Item {field1 = "opuytj"}
}).Save();
DB.Update<Item>()
.Match(_ => true)
.WithPipelineStage("{$set : { field2 : { $substr: [ '$field1', 0, 2 ] } }}")
.ExecutePipeline();
}
}
}
Please use find with forEach keyword
db.demo.find({}).forEach( function(myDoc) {
var condname=myDoc.name;
var condcat=myDoc.category;
var replaceName =condcat.substring(0,2);
db.demo.update({_id: myDoc._id}, {$set : {"name": replaceName }},
{upsert:false, multi:true})
} );

How to add key to $addToSet in mongoDB

I want to add a key inside mongodb add function. I am doing this right now.
$addToSet : {
"msges":{
time:{"from":uname,"title":title,"msg":msg,"read":false}
}
}
time is a variable that is coming from the paramater. It has time inside it as hh:mm:ss A. But when the query runs, instead of time as key, string "time" gets print as key. Any ideas what should I do?
Enclose your variable in [] :
$addToSet: {
"msges": {
[time]: { "from": uname, "title": title, "msg": msg, "read": false }
}
}
For instance :
var myfield = "custom_field";
db.test.update({
_id: 1
}, {
$addToSet: {
letters: [{
[myfield]: 1
}, {
[myfield]: 2
}]
}
})
It gives :
{ "_id" : 1, "letters" : [ [ { "custom_field" : 1 }, { "custom_field" : 2 } ] ] }

How to add an array to an existing collection in mongoDb

I need to add an array of data to an existing collection in mongoDb.
suppose my existing collection, say "planetSystem" is of type:
{
"_id":"123123123",
"key1":"value1",
"key2":"value2"
}
i need to add an array of the following type
[
{
"amount":"678",
"addedBy":"idontknow"
"commission":"100"
} ,
{
"amount":"800",
"addedBy":"iwishiknew"
"commission":"108"
}
]
so that the final collection looks like this
{
"_id":"123123123",
"key1":"value1",
"key2":"value2",
[
{
"amount":"678",
"addedBy":"idontknow"
"commission":"100"
} ,
{
"amount":"800",
"addedBy":"iwishiknew"
"commission":"108"
}
]
}
i need help in the update query part of this.
Thanks
You will have to add key to PlanetSystem collection,
var planetSystem= {
"_id":"123123123",
"key1":"value1",
"key2":"value2" };
var arr = [{
"amount":"678",
"addedBy":"idontknow"
"commission":"100"
} ,
{
"amount":"800",
"addedBy":"iwishiknew"
"commission":"108"
}];
Add new key
planetSystem.arr = arr;
Result,
var planetSystem={
"_id": "123123123",
"key1": "value1",
"key2": "value2",
"arr": [{
"amount": "678",
"addedBy": "idontknow",
"commission": "100"
}, {
"amount": "800",
"addedBy": "iwishiknew",
"commission": "108"
}]}