Graphcool (Graphql): how to make exact filter in array of Id - filtering

I have chat model
type Chat #model {
id: ID! #isUnique
name: String
messages: [Message!]! #relation(name: "ChatMessages")
users: [User!]! #relation(name: "ChatUser")
createdAt: DateTime!
}
And I've created a chat with two people ["123", "234"] and all was ok. But when I want to create a new group chat with three people where two of them already have a chat with themselves ["123", "234", "345"]
I make a query for check is this chat exist with three people
query {
allChats(filter:{
users_every: {
id_in: ["123", "234", "345"]
}
}
){
id
users{
id
}
}
}
and I got response that this chat already exist, but here I have just two users not all of them
{
"data": {
"allChats": [
{
"id": "cjgxuub2351uj0187qeil548m",
"users": [
{
"id": "123"
},
{
"id": "234"
}
]
}
]
}
}

The every suffix in users_every makes sure it matches all chats that have only users with ids from the id_in array. That's why you're getting chats with fewer users, because subsets match.
The solution:
query {
allChats(
filter: {
AND: [
{ users_some: { id: "123" } },
{ users_some: { id: "234" } },
{ users_some: { id: "345" } },
{ users_every: { id_not_in: ["678", "910", ...] } }
]
}
) {
id
users {
id
}
}
}
The users_some filters make sure to select chats that have at least all those 3 users attached. The users_every - id_not_in is needed to exclude the chats with those three plus any other users.
In all honesty this seems a bit convoluted to me, and probably kinda unfeasible for an app with a large number of users. I'd love for graph.cool to implement some easier solution in the api.
As an alternative, you could just omit the users_every filter, and then, in your client app, pick from the results only the chat that has exactly 3 users.

Related

MongoDB $addToSet inside another $addToSet

I am trying to achieve the below response from query.
{
users:[
user:{
name:"",
email:[
]
},
....user2
]
}
I have something similar to below.
I will put this way. One user can have n number of devices. He may have more than one email per device. I want to group at devices. And user field should have common information for that device. As we think, name will always be same. Device specific attributes also needed like whatKindOfDevice, howManyIssuesAreThereInThatDevice, howManyCanBeAddressedByUpgrade, howManyAreRare,etc.. along with this i need to get all the emails used in that device like owner,user,associate - all emails put.
Think my document Id is not associated with single user, single device. One user can have any number of devices. One device can have n Number of documents.
$group:{
"_id":"user_device_id",
"user": {
"$addToSet": {
"name":"$name",
"deviceName":"$deviceName",
"email": {"$addToSet":{}} //Something Similar I am expecting
}
}
}
If I add email outer user it works - but it affects the response format required.
Is it possible or any other way to get it the similar response through the query?
Let's assume one user can have more than one document. In each doc, there could be same or duplicate email IDs. I am trying to get that together.
Please advise.
Sample Doc:
{
_id:ObjectId,
name:"user1",
email:"a#yahoo.com"
},
{
_id:ObjectId,
name:"user1",
email:"a#device.com"
},
..user2Doc
..user1Doc with another category, duplicate email i.e a#yahoo.com
..user2Doc with new email
..
Well, it seems like you want to get all the email for the particular user and then group all the users.
So, to achieve that you have to do consecutive grouping stages.
I used the below documents:
[
{
name:"user1",
email:"a#yahoo.com"
},
{
name:"user1",
email:"a#device.com"
},
{
name:"user2",
email:"b#yahoo.com"
},
{
name:"user1",
email:"c#device.com"
}
]
Here is the query:
db.collection.aggregate([
{
$group:{
"_id":"$name",
"emails":{
$addToSet:"$email"
},
"name":{
$first:"$name"
}
}
},
{
$group:{
"_id":null,
"users":{
$addToSet:{
"name":"$name",
"email":"$emails"
}
}
}
},
{
$project:{
"_id":0
}
}
]).pretty()
Output:
{
"users" : [
{
"name" : "user1",
"email" : [
"c#device.com",
"a#device.com",
"a#yahoo.com"
]
},
{
"name" : "user2",
"email" : [
"b#yahoo.com"
]
}
]
}
For mare about $group refer here.
Hope this will help :)

mongo db how to store multi relation like graph

I have to store some users and their group relations like below
So I am planning to create a collection like below
UserGroupRelation Collections
{
"user":String,
"Group":String"
}
example of collections for Super admin users
{
"user":"Adminuser-1",
"Group":"Group1"
}
{
"user":"Adminuser-1",
"Group":"Group2"
}
{
"user":"Adminuser-1",
"Group":"Group3"
}
where user & Group column is indexed and I will run below kind of query
1.Whenever I want to check whether given user has access to the given group
db.UserGroupRelation.find( { user: "Adminuser-1", Group: "Group2" })
2.Also I want to delete all the association whenever we delete group
db.UserGroupRelation.deleteMany({ Group: "Group2" })
3.Also find all the users of a group
db.UserGroupRelation.find( { Group: "Group2" })
4.Find Hierarchy?, with my Approach I am not able to find
But with this approach I am duplicating lot of data also in real time I may have 10000 groups and 1 million user so there would be performance issue. And with this I am not able to maintain a hierarchy like SuperAdmin->SubAdmin->user of same group
I checked with mongo tree but it is not fitting to this requirement. is there a better way to handle this requirement in mongodb .?
This is the structure your graphic requirements show. It does still lead to repetition though so you will need to change it. Read up on one-many relationships.
{
"superAdmin_ID": "001",
"groups": [
{
"_id": "0",
"groupNumber": "1",
"users": [
{
"_userKey": "1023"
"userName": "Fred"
},
{
"_userKey": "1024"
"userName": "Steve"
}
],
"subAdmin": {
"_adminKey": "55230"
"adminName": "Maverick"
},
},
{
"_id": "1",
"groupNumber": "2",
"users": [
{
"_userKey": "1023"
"userName": "Fred"
},
{
"_userKey": "4026"
"userName": "Ella"
}
],
"subAdmin": {
"_adminKey": "55230"
"adminName": "Maverick"
},
},
{
"_id": "2",
"groupNumber": "3",
"users": [
{
"_userKey": "7026"
"userName": "James"
}
],
"subAdmin": {
"_adminKey": "77780"
"adminName": "Chloe"
},
},
]
}
You can also make subAdmin an array if you need more than one subAdmin within a group.

How to query an object in an array embedded in mongodb?

I am currently working on an application that takes control of Projects, which have Meetings and that these meetings have Participants.
I want to consult a Participant by his nomina field.
Structure for a project document object:
{
"id":"5c1b0616a0441f27f022bfdc",
"name":"Project Test",
"area":"Area",
"date":"2019-01-01",
"meetings":[
{
"id":"5c1b073d445707834699ce97",
"objetive":"Objetive",
"fecha":"2019-01-01",
"participants":[
{
"nomina":1,
"name":"Person 1",
"role":"Rol1",
"area":"area1",
"signature":null
},
{
"nomina":2,
"name":"Person 2",
"role":"rol 2",
"area":"área 2",
"signature":null
}
]
}
]
}
Expected behavior
I want to consult a Participant by nomina field knowing the id of the Project and also knowing the id of the Meeting.
Expected output
Having:
id Project = 5c1b0616a0441f27f022bfdc
id Meeting = 5c1b073d445707834699ce97
nomina Participant = 1
It's expected that the query will return me:
{
"nomina":1,
"name":"Person 1",
"role":"Rol1",
"area":"area1",
"signature":null
}
For not so huge number of meetings in every document if you want to get the exact document stated, you can do this pipeline, it is straight forward:
db.collection.aggregate(
[
{
$match: {
id:"5c1b0616a0441f27f022bfdc"
}
}, {
$unwind: {
path : "$meetings"
}
},
{
$unwind: {
path : "$meetings.participants"
}
},
{
$match: {
"meetings.id":"5c1b073d445707834699ce97",
"meetings.participants.nomina":1
}
},
{
$replaceRoot: {
newRoot: "$meetings.participants"
}
}
]);
If you would have over thousands of elements in meetings then I'd suggest adding another match to meetings or grouping meetings and project IDs.
But if you just want to get the document containing what you want it is just a simple find query:
db.collection.find({id:"5c1b0616a0441f27f022bfdc","meetings.id":"5c1b073d445707834699ce97","meetings.participants.nomina":1 });

Get Last Arrays Item in Several Nested Fields in MongoDB

I have a dynamic nested fields like user.com1.grp1.history which history is a set of hash tables.
Sample structure:
{
_id: "123456",
user: {
com1: {
grp1: {
history: [
{
action: "something",
...
}
...
]
},
grp2: {
history: [
{
action: "something else"
...
}
...
]
},
},
com2: {
...
}
}
}
When I want to get last item of history for grps, this way works fine:
db.user.find({}, {user.com1.grp1.history: {$slice: -1}})
But the problem is here that coms and grps are dynamic names and each user contains many dynamic coms and each com contains many dynamic grps and I can't call query for each of them.
So how can I get last items of each com/grp's history in this situation?

Where filter with HasAndBelongsToMany relation in Loopback

first of all I am sorry if this has been asked 1st, I searched for this and got few links but wasn't helpful.
I am working on simple chat application created in Angular 4 which has Customer entity and Conversation entity and Message. In The customer => hasAndBelongsToMany => Conversation with MongoDb Connector.
In customer.json
"relations": {
"conversations": {
"type": "hasAndBelongsToMany",
"model": "Conversation"
}
}
In conversation.json
"relations": {
"customers": {
"type": "hasAndBelongsToMany",
"model": "Customer"
}
}
This creates table customerconversation which contains conversationId and customerId
Now basically I want to find conversation for two customer Ids, So I tried following filters but it doesn't seem to work and always returns empty array even though there is conversation having these two customer ids.
let filter = {
where: {
and: [
{
customers: {
inq: [
this.customerId // = 59bb981f35fcc941e8ba64e4
]
}
},
{
customers: {
inq: [
this.authService.getCurrentId() // = 59bb98c735fcc941e8ba68ff
]
}
}
]
}
};
and another without and operator
let filter = {
where: {
customers: {
inq: [
this.customerId, // 59bb981f35fcc941e8ba64e4
this.authService.getCurrentId() // 59bb98c735fcc941e8ba68ff
]
}
}
};
These both returns customer with mentioned Id but with 0 conversations. I know I can get all conversations of specific customer by using include filter for conversations but still those would need to be filtered as I want single conversation of this customer with another specific customer.
You can get the information by grabbing the customer first and then using the relations and include to get the data you need.
Example is based on the assumption that you are writing this using typescript & loopback-sdk-builder on an angular application.
this.customerApi
.getConversations(this.authService.getCurrentId(), {
where: {
customerId: this.customerId
})
.subscribe(result => {
// your logic here
})