简体   繁体   中英

arangodb AQL query to erase list and it's child depending of condition

I have a collection of Accounts that has a list of Logs

I need to erase each Log of the Account's "logs" list if "loggedAt" field of Log is older than 5 days, without leaving orphan Logs or corrupt the references of the "logs" list.

How can i achieve this using AQL or arangosh command?

Something like this

FOR a IN account
 FOR l IN log

FILTER l._id IN a.logs
FILTER DATE_DIFF(l.loggedAt, DATE_NOW(), 'days', false) > 5

UPDATE a WITH { logs: REMOVE_VALUE( a.logs, l ) } IN account
REMOVE { _key: l._key } IN log

Account document example

_id:account/1085466856
_rev:_bIYHFNu---
_key:1085466856
{
  "_class": "com.app.Account",
  "logs": [
    "log/1085468455",
    "log/1085468456",
    "log/1085468457"
  ]
}

Account.class

@Data
@Document("account")
public class Account implements Serializable {

    private static final long serialVersionUID = -1615384653229054932L;

    @Id
    private String id;

    @Ref(lazy = false)
    private Collection<Log> logs;
}

Log document example

_id:log/1085468455
_rev:_bHhi2zu-_1
_key:1085468455
{
  "_class": "com.app.Log",
  "loggedAt": "2020-08-24T17:44:43.600Z"
}

Log.class

@Data
@Document("log")
public class Log implements Serializable {

    private static final long serialVersionUID = -1969696942832711654L;

    @Id
    private String id;

    private Date loggedAt;

}

You can make this in 2 AQL queries:

  1. Remove logs first:
LET fiveDaysAgo = DATE_SUBTRACT(DATE_NOW(), 5, 'days')
FOR rec IN log
  FILTER DATE_DIFF(rec.loggedAt, fiveDaysAgo, 'days') >= 0
  REMOVE rec IN log
  1. Clean accounts next:
FOR acc IN account
  LET validLogs = (
    FOR accLog IN acc.logs
      FOR rec IN log
        FILTER accLog == rec._id
        RETURN rec._id
  )
  FILTER LENGTH(acc.logs) != LENGTH(validLogs)
  UPDATE acc WITH {logs: validLogs} IN account

It is possible to put the queries above into one query if needed:

LET fiveDaysAgo = DATE_SUBTRACT(DATE_NOW(), 5, 'days')
FOR acc IN account
  LET invalidLogs = (
    FOR accLog IN acc.logs
      FOR rec IN log
        FILTER accLog == rec._id
        FILTER DATE_DIFF(rec.loggedAt, fiveDaysAgo, 'days') >= 0
        REMOVE rec IN log
        RETURN OLD._id
  )
  FILTER LENGTH(invalidLogs) > 0
  UPDATE acc WITH {logs: OUTERSECTION(acc.logs, invalidLogs)} IN account

However, if you have zombie records in the log collection (records without any association with an account record) the query above leaves them untouched.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM