I am trying to $push
an Object
into a nested array, however it doesn't seem to be working. I am not sure what I am doing wrong.
My database is like this:
{
customers: {
name: String,
address: String,
proj_managers: [
{
name: String,
username: String,
projects: [
name: String,
tags: [
{
tag_no: Number,
tag_id: String,
time: String,
product_id: String,
urls: [
url: String,
count: Number
],
gps: String,
deactivate: Boolean
}
]
]
}
]
}
}
So what I want to do is $push
an array of tags into tags
, for a specific project
. My backend uses GraphQL
:
/index.js
// GraphQL schema
import schema from './schema'
// Mongoose Models
import Customer from './models/Customer'
import Manager from './models/Manager'
// Access to GraphQL API
app.use('/graphql', bodyParser.json(), graphqlExpress({ schema, context: { Customer, Manager } }))
app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }))
/schema/index.js
import { bundle } from 'graphql-modules'
import { makeExecutableSchema } from 'graphql-tools'
// GraphQL Modules
import Manager from './Manager'
import Customer from './Customer'
import ProjectManager from './ProjectManager'
import Project from './Project'
import Tag from './Tag'
import URL from './URL'
const modules = [Manager, Customer, ProjectManager, Project, Tag, URL]
export default makeExecutableSchema(bundle(modules))
/schema/Project.js
const schema = `
type Project {
_id: ID,
name: String!,
description: String,
tags: [Tag],
deactivate: Boolean!
}
input TagInput {
tagNo: Int!,
tagId: String!,
time: String,
productId: String,
url1: String,
url2: String,
gps: String
}
`
const queries = `
projects(customerUsername: String!): [Project],
project(projectID: ID!): Project
`
const mutations = `
editProject(id: ID!, name: String, description: String, deactivate: Boolean, customerUsername: String!, pmUsername: String!): String,
addProject(name: String!, description: String, customerID: ID!, pmUsername: String!): String,
pushTags(customerID: String!, username: String!, projectID: ID!, isManager: Boolean!, tags: [TagInput]!): String
`
const pushTags = async (root, { tags, customerID, username, projectID, isManager }, { Customer }) => {
let result = ''
let query = { _id: customerID }
let update = {}
let ts = []
let options = {
arrayFilters: [
{ 'a.username': username },
{ 'b._id': projectID }
]
}
tags.forEach(tag => {
if (isManager) {
ts.push({
tag_no: tag.tagNo,
tag_id: tag.tagId,
time: new Date(),
product_id: tag.productId,
urls: [
{ url: tag.url1, count: 0 },
{ url: tag.url2, count: 0 }
],
gps: tag.gps,
deactivate: false
})
} else {
update = {
$set: {
'proj_managers.$[a].projects.$[b].tags': {
product_id: tag.productId,
urls: [
{ url: tag.url1 },
{ url: tag.url2 }
],
gps: tag.gps
}
}
}
}
})
if (isManager) {
update = {
$push: {
'proj_managers.$[a].projects.$[b].tags': {
$each: ts
}
}
}
result = await Customer.update(query, update, options)
}
return result.ok && result.nModified ? 'Success' : 'Failed'
}
const resolvers = {
queries: {
projects,
project
},
mutations: {
addProject,
editProject,
pushTags
}
}
export default () => ({
schema,
queries,
mutations,
resolvers
})
The tags that are being sent to pushTags
mutation is:
[
{
"tagNo":"1",
"tagId":"02F9AMCGA38O7L",
"productId":"",
"url1":"",
"url2":"",
"gps":""
},{
"tagNo":"2",
"tagId":"028MFL6EV5L904",
"productId":"",
"url1":"",
"url2":"",
"gps":""
},{
"tagNo":"3",
"tagId":"02XDWCIL6W2IIX",
"productId":"",
"url1":"",
"url2":"",
"gps":""
}
];
The Document
{
"_id": ObjectId("5b0216f1cf14851f18e4312b"),
"deactivate": false,
"name": "Razer",
"address": "201 3rd Street, Suite 900 San Francisco, CA 94103 USA",
"phone_no": "0987654321",
"proj_managers": [
{
"deactivate": false,
"_id": ObjectId("5b021750cf14851f18e4312c"),
"name": "Liang-Shih Lin",
"username": "troopy",
"phone_no": "0987654321",
"password": "$2b$10$eOVoRkfmkHQyHkc6XaDanunUuyi0EFy.oZ.dRgKJYxBciMLYUVy0W",
"projects": [
{
"deactivate": false,
"_id": ObjectId("5b0217d4cf14851f18e4312d"),
"name": "Razer Godzilla",
"description": "A Godzilla Mouse",
"tags": [ ]
}
]
}
],
"__v": 0
}
I have tried using findByIdAndUpdate
, updateOne
, using a forEach()
helper function to loop through the tags and $push
it into the database one by one, but nothing seems to be working. I thought it could be my arrayFilters
, I changed b._id
to b.name
but that didn't work either.
I tried using this in the mongo
shell, with this query:
db.customers.update({ _id: "5afe642ed42aee261cb3292e" }, { $push: { "proj_managers.$[a].projects.$[b].tags": { tag_no: 1, tag_id: "0476F06A594980", time: "2018-05-20T23:18:18.824Z", product_id: "xr235Yf4", urls: [{url: "example.com", count: 0}, {url: "example2.com", count: 0}], gps: "", deactivate: false} } }, { arrayFilters: [{ "a.username": "joliver" }, { "b.id": "5b01367b6d053860e90e0f9f" }] })
The result:
WriteResult({
"nMatched": 0,
"nUpserted": 0,
"nModified": 0
})
If you want to take a look at the whole project, here is the link